Sixty years since Silent Spring: a map of meta-analyses on organochlorine pesticides reveals urgent needs for improving methodological quality

Kyle Morrison, Coralie Williams, Lorenzo Ricolfi, Yefeng Yang, Malgorzata Lagisz, Shinichi Nakagawa

2023-03-09

In this Rmarkdown document we provide the following workflow:

  • Section 0: To examine the volume and temporal trends of existing meta-analyses on the effects of organochlorine pesticides

  • Section 1: To evaluate the methodological patterns and quality of existing meta-analyses studying the effects of organochlorine pesticides.

  • Section 2: To explore the various characteristics of the organochlorine pesticides literature such as the pesticides used, the impacts elicited in response and the subjects that were investigated.

  • Section 3: To investigate the research outputs across different countries, continents and disciplines, and investigate the degree of cross-country collaboration.

Load packages and data

Load packages

rm(list = ls())
pacman::p_load(tidyverse,
hrbrthemes, 
patchwork,
here,
stringr,
knitr,
formatR,
forcats,
ggplot2,
bibliometrix,
ordinal,
igraph,
stringi,
stringdist,
circlize,
ggalluvial,
ggraph,
ComplexUpset)
knitr::opts_chunk$set(echo = TRUE, message = FALSE, warning = FALSE)

Load data

Manually extracted pilot data is stored in five separate .csv files representing different aspects of the data (extracted via structured predefined Google Forms - one per table). Bibliographic data records are exported from Scopus (including cited references field) in .bib format and locally saved as bib_sco.bib.

# Load CSV datasets
sd <- read_csv(here("data", "ocp_srm_study_details.csv"))
ocp <- read_csv(here("data", "ocp_srm_ocp_details.csv"))
sub <- read_csv(here("data", "ocp_srm_subject_details.csv"))
im <- read_csv(here("data", "ocp_srm_impact_details.csv"))
sp <- read_csv(here("data", "ocp_srm_species_details.csv"))
pol <- read_csv(here("data", "ocp_srm_policy.csv"))
# Load BibTeX dataset
bib_sco <- convert2df(here("data", "bib_sco.bib"), dbsource = "scopus", format = "bibtex")

Section 0

To examine the volume and temporal trends of existing meta-analyses on the effects of organochlorine pesticides

Figure 1

  1. Bar chart showing the annual number of meta-analyses synthesising research on the impacts of organochlorine pesticides, categorised by different subjects of exposure.
  2. Area graph showing the cumulative time trends of meta-analyses synthesising research on the impacts of organochlorine pesticides, categorised by different subjects of exposure.
  3. Bar chart showing the annual number of policy citations on the included meta-analysis analyses synthesising research on the impacts of organochlorine pesticides, categorised by policy topics
  4. Area graph showing the cumulative time trends of policy citations on the included meta-analysis analyses synthesising research on the impacts of organochlorine pesticides, categorised by policy topics
# Join the study and subject datasets
sd_sub <- left_join(sd, sub, by = "study_id")

# Count the number of publications per year and calculate cumulative sum
sd1 <- sd %>%
  count(publication_year) %>%
  mutate(n_cumulative = cumsum(n))

# Custom theme ensuring consistent formatting
theme_count <- function() {
  theme_minimal() +
    theme(
      panel.grid.major.y = element_line(color = "gray", linetype = "dashed"),
      panel.grid.minor.y = element_blank(),
      axis.line.x = element_line(size = 1.2),
      axis.line.y = element_line(size = 1.2),
      axis.title.x = element_text(size = 20, face = "bold"),
      axis.title.y = element_text(size = 20, face = "bold"),
      axis.text.x = element_text(angle = 45, hjust = 1, size = 15, color = "#666666"),
      axis.text.y = element_text(size = 20, color = "#666666"),
      legend.position = "none"  # Hide legend by default
    )
}

# Set fixed year range
min_year <- 1993
max_year <- 2022

fig1a <- sd_sub %>%
  mutate(subjects = strsplit(subject, ",\\s+")) %>%
  unnest(subjects) %>%
  count(publication_year, subjects) %>%
  group_by(subjects = reorder(subjects, n)) %>%
  ggplot(aes(x = publication_year, y = n, fill = subjects)) +
  geom_bar(stat = "identity", position = "stack", alpha = 0.7) +
  geom_text(
    aes(label = n),
    position = position_stack(vjust = 0.6),
    fontface = "bold", 
    color = "white", 
    size = 6, 
    hjust = 0.4
  ) +
  scale_x_continuous(
    breaks = seq(min_year, max_year, by = 1),
    limits = c(min_year, max_year + 1),  # Add 1 year beyond max_year
    expand = expansion(0, 0)            # No extra gap at edges
  ) +
  scale_y_continuous("Annual Article Count", limits = c(0, 15)) +
  # Use plotmath expression to make the title bold and underlined
  labs(
    title = expression(bold(underline("Articles"))),
    y = "Article Count", 
    tag = "A", 
    fill = "Subjects"
  ) +
  theme_count() +
  theme(
    # Make title bigger
    plot.title = element_text(size = 26),
    axis.title.x = element_blank(),
    legend.position = c(0, 1),
    legend.justification = c(0, 1),
    legend.box.just = "left",
    legend.text = element_text(size = 14, face = "bold"),
    legend.title = element_text(size = 16, face = "bold")
  ) +
  scale_fill_brewer(palette = "Dark2") +
  guides(
    fill = guide_legend(
      title = "Subjects", 
      override.aes = list(alpha = 0.7, size = 8)
    )
  )

# Create the cumulative count plot for articles (fig1b) - Hides legend
fig1b <- sd_sub %>%
  mutate(subjects = strsplit(subject, ",\\s+")) %>%
  unnest(subjects) %>%
  count(publication_year, subjects) %>%
  group_by(subjects = reorder(subjects, n)) %>%
  mutate(n_cumulative = cumsum(n)) %>%
  ggplot(aes(x = publication_year, y = n_cumulative, fill = subjects)) +
  geom_area(size = 1.2, alpha = 0.7) +  # Ensuring consistent alpha
  scale_y_continuous("Cumulative Article Count", limits = c(0, 125), expand = expansion(0, 0)) +
  scale_x_continuous(
    breaks = seq(min(sd_sub$publication_year), max(sd_sub$publication_year), by = 1), 
    expand = expansion(0,0)
  ) +  
  labs(x = "Year", y = "Cumulative Article Count", tag = "B") +
  theme_count() +
  scale_fill_brewer(palette = "Dark2") +
  theme(
    legend.position = "none"  # Remove legend from this plot
  )

fig1c <- ggplot(
  pol %>%
    filter(!is.na(policy_title)) %>%
    mutate(policy_topic = strsplit(policy_topic, ";\\s+")) %>%
    unnest(policy_topic) %>%
    group_by(policy_topic) %>%
    mutate(total_count = n()) %>%
    ungroup() %>%
    mutate(policy_topic = if_else(total_count < 7, "Other", policy_topic)) %>%
    filter(policy_year <= 2023) %>%
    count(policy_year, policy_topic) %>%
    complete(
      policy_year = 1993:2022,
      policy_topic = unique(policy_topic),
      fill = list(n = 0)
    ),
  aes(x = policy_year, y = n, fill = policy_topic)
) +
  geom_bar(stat = "identity", position = "stack", alpha = 0.7) +
  geom_text(
    aes(label = ifelse(n > 1, n, "")),
    position = position_stack(vjust = 0.6),
    fontface = "bold",
    color = "white",
    size = 6,
    hjust = 0.4
  ) +
  scale_x_continuous(
    breaks = 1993:2022,              
    limits = c(1993, 2023),          
    expand = expansion(0, 0)
  ) +
  scale_y_continuous(
    "Annual Policy Citations", 
    limits = c(0, 40),
    expand = expansion(0, 0)
  ) +
  labs(
    # Use plotmath expression here as well
    title = expression(bold(underline("Policy"))),
    x = "Year",
    y = "Annual Policy Citations", 
    tag = "C", 
    fill = "Policy Topics"
  ) +
  theme_count() +
  scale_fill_brewer(palette = "Dark2") +
  theme(
    # Make title bigger
    plot.title = element_text(size = 26),
    axis.title.x = element_blank(),
    legend.position = c(0.0, 1),
    legend.justification = c(0, 1),
    legend.box.just = "left",
    legend.text = element_text(size = 14, face = "bold"),
    legend.title = element_text(size = 16, face = "bold")
  ) +
  guides(
    fill = guide_legend(
      title = "Topics",
      override.aes = list(alpha = 0.7, size = 8)
    )
  )

# Create fig1d
fig1d <- pol %>%
  filter(!is.na(policy_title)) %>%
  mutate(policy_topic = strsplit(policy_topic, ";\\s+")) %>%
  unnest(policy_topic) %>%
  group_by(policy_topic) %>%
  mutate(total_count = n()) %>%
  ungroup() %>%
  mutate(policy_topic = if_else(total_count < 7, "Other", policy_topic)) %>%
  filter(policy_year < 2023) %>%
  count(policy_year, policy_topic) %>%
  complete(
    policy_year = 1993:2022,
    policy_topic = unique(policy_topic),
    fill = list(n = 0)
  ) %>%
  group_by(policy_topic) %>%
  arrange(policy_year, .by_group = TRUE) %>%
  mutate(n_cumulative = cumsum(n)) %>%
  ungroup() %>%
  ggplot(aes(x = policy_year, y = n_cumulative, fill = policy_topic)) +
  geom_area(size = 1.2, alpha = 0.7) +
  scale_y_continuous(
    "Cumulative Policy Citations", 
    limits = c(0, 250), 
    expand = expansion(0, 0)
  ) +
  scale_x_continuous(
    breaks = 1993:2022,
    expand = expansion(0, 0)
  ) +
  labs(
    x = "Year",
    y = "Cumulative Policy Citations", 
    tag = "D"
  ) +
  theme_count() +
  scale_fill_brewer(palette = "Dark2") +
  theme(
    legend.position = "none"
  )

# Combine plots, ensuring the legend only appears in fig1a and fig1c
fig1 <- fig1a / fig1b / fig1c / fig1d

# Display the final combined plot
fig1

# Save the final figure
ggsave(
  here("figures", "fig1.pdf"), 
  width = 16, height = 24, units = "cm", 
  scale = 2, dpi = 800
)

# Combine plots, ensuring the legend only appears in fig1a
fig1 <- fig1a / fig1b / fig1c / fig1d

# Display the final combined plot
fig1

# Save the final figure
# ggsave(here("figures", "fig1.pdf"), width = 16, height = 24, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "fig1.jpg"), width = 16, height = 24, units = "cm", scale = 2, dpi = 800)

Policy country bar plot

Bar chart showing the annual number of policy citations on the included meta-analysis analyses synthesising research on the impacts of organochlorine pesticides, categorised by country

policy_country <- ggplot(
  pol %>%
    # 1) Remove rows with NA policy_title
    filter(!is.na(policy_title)) %>%
    # 2) Split multi-country strings on semicolon and unnest
    mutate(policy_country = strsplit(policy_country, ";\\s+")) %>%
    unnest(policy_country) %>%
    # 3) Lump any country used fewer than 7 times overall
    group_by(policy_country) %>%
    mutate(total_count = n()) %>%
    ungroup() %>%
    mutate(policy_country = if_else(total_count < 5, "Other", policy_country)) %>%
    # 4) Keep only years <= 2023
    filter(policy_year <= 2023) %>%
    # 5) Count number of policies per (year, country)
    count(policy_year, policy_country) %>%
    # 6) Complete missing (year, country) combos from 1993 to 2022 with n = 0
    complete(
      policy_year = 1993:2022,
      policy_country = unique(policy_country),
      fill = list(n = 0)
    ),
  aes(x = policy_year, y = n, fill = policy_country)
) +
  geom_bar(stat = "identity", position = "stack", alpha = 0.7) +
  geom_text(
    aes(label = ifelse(n > 0, n, "")),
    position = position_stack(vjust = 0.6),
    fontface = "bold", color = "white", size = 6, hjust = 0.4
  ) +
  scale_x_continuous(
    breaks = 1993:2022,              
    limits = c(1993, 2023),          
    expand = expansion(0, 0)
  ) +
  scale_y_continuous(
    "Annual Policy Citations", 
    limits = c(0, 40),      # Adjust if you want a different max on the y-axis
    expand = expansion(0, 0)
  ) +
  labs(
    x = "Year",
    y = "Annual Policy Citations", 
    fill = "Policy Countries"
  ) +
  theme_count() +
  scale_fill_brewer(palette = "Dark2") +
  theme(
    axis.title.x = element_blank(),
    legend.position = c(0.0, 1),   # Top-left
    legend.justification = c(0, 1),
    legend.box.just = "left"
  ) +
  guides(
    fill = guide_legend(
      title = "Policy Countries",
      override.aes = list(alpha = 0.7, size = 8)
    )
  )

# ggsave(here("figures", "policy_country.pdf"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "policy_country.jpg"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)

Create a standard theme for the supplementary plots

organochlorTHEME <- function() {
  theme_minimal() +
  theme(
    title = element_text(size = 30),
    axis.text.y = element_text(size = 30),
    axis.text.x = element_text(size = 20),
    axis.line.x = element_line(color = "gray", size = 3),
    axis.line.y = element_blank(),
    axis.ticks.x = element_blank(),
    axis.ticks.y = element_blank(),
    axis.title.x = element_blank(),
    axis.title.y = element_blank(),
    panel.grid.major.y = element_blank(),
    panel.grid.minor.y = element_blank(),
    legend.position = "none")    
}

Section 1

To evaluate the methodological quality and patterns of existing meta-analyses studying the effects of organochlorine pesticides.

Figure 2

The methodological and reporting quality of meta-analyses according to CEESAT v. 2.1 (Woodcock et al., 2014). Scores are represented by the following colours: gold is regarded as the highest (best) score, green is second highest score, amber is second-lowest score, and red is the lowest (worst) score. The total counts of studies allocated to each score are shown in each bar. All CEESAT v. 2.1 items, along with our interpretation, are provided in Supplementary File 2.

Figure 2a

CEESAT scores for 83 assessed meta-analyses

# Start the data manipulation
percent_ceesat_score <- sd %>%
  filter(!is.na(author_year)) %>%
  select(studies = author_year, starts_with("CEE")) %>%
  na.omit() %>%
  pivot_longer(cols = -studies, names_to = "question", values_to = "score") %>%
  group_by(question, score) %>%
  summarise(n = n(), .groups = 'drop') %>%
  mutate(percent = (n/sum(n))*100, 
         across(c(question, score), as.factor),
         question = fct_recode(question, 
           `1.1 Are the elements of the review question clear?` = "CEESAT2_1.1",
           `2.1 Is there an a-priori method protocol document?` = "CEESAT2_2.1",
           `3.1. Is the approach to searching clearly defined systematic and\ntransparent?` = "CEESAT2_3.1",
           `3.2. Is the search comprehensive?` = "CEESAT2_3.2",
           `4.1. Are eligibility criteria clearly defined?` = "CEESAT2_4.1",
           `4.2. Are eligibility criteria consistently applied to all potentially relevant\narticles and studies found during the search?` = "CEESAT2_4.2",
           `4.3. Are eligibility decisions transparently reported?` = "CEESAT2_4.3",
           `5.1. Does the review critically appraise each study?` = "CEESAT2_5.1",
           `5.2. During critical appraisal was an effort made to minimise\nsubjectivity?` = "CEESAT2_5.2",
           `6.1. Is the method of data extraction fully documented?` = "CEESAT2_6.1",
           `6.2. Are the extracted data reported for each study?` = "CEESAT2_6.2",
           `6.3. Were extracted data cross checked by more than one reviewer?` = "CEESAT2_6.3",
           `7.1. Is the choice of synthesis approach appropriate?` = "CEESAT2_7.1",
           `7.2. Is a statistical estimate of pooled effect provided together with\nmeasure of variance and heterogeneity among studies?` = "CEESAT2_7.2",
           `7.3 Is variability in the study findings investigated and discussed?` = "CEESAT2_7.3",
           `8.1 Have the authors considered limitations in the synthesis?` = "CEESAT2_8.1"),
         question = factor(question, levels = rev(levels(question))),
         score = factor(score, levels = levels(score)[c(4,1,3,2)]))

# Create CEESAT plot 
fig2a <- ggplot(data = percent_ceesat_score, aes(x = question, y = percent, fill = score)) +
  geom_col(width = 0.7, position = "fill", color = "black") +
  geom_text(aes(label = n), position = position_fill(vjust = 0.5), size = 7, fontface = "bold") +
  coord_flip() +
  guides(fill = guide_legend(reverse = TRUE)) +
  scale_fill_manual(values = c("#FF0000","#FFD700","#008000", "#DAA520"), name = "Score:") +
  scale_y_continuous(labels = scales::percent) +
  theme(panel.grid.major = element_blank(), 
        panel.grid.minor = element_blank(), 
        panel.background = element_blank(),
        axis.text.y = element_text(size = 20),
        axis.text.x = element_text(size = 20),
        axis.title.x = element_text(size = 25),
        axis.title.y = element_text(size = 25), 
        legend.position = "top",  
        legend.justification = "left",  
        legend.direction = "horizontal",
        legend.box = "horizontal",  
        legend.box.just = "left",  
        legend.title.align = 0.5,  
        legend.key.size = unit(1, "cm"),  
        legend.title = element_text(size =25),
        legend.text = element_text(size = 25),  
        strip.text = element_text(size = 20),
        strip.background = element_blank(), 
        plot.tag = element_text(size = 25)) + 
  ylab("Percentage") + 
  xlab("CEESAT Question") +  
  labs(tag = "A")

fig2a

total_n <- sum(percent_ceesat_score$n)
percentages <- tibble(
  red_percentage = sum(percent_ceesat_score$n[percent_ceesat_score$score == "Red"]) / total_n * 100,
  amber_percentage = sum(percent_ceesat_score$n[percent_ceesat_score$score == "Amber"]) / total_n * 100,
  green_percentage = sum(percent_ceesat_score$n[percent_ceesat_score$score == "Green"]) / total_n * 100,
  gold_percentage = sum(percent_ceesat_score$n[percent_ceesat_score$score == "Gold"]) / total_n * 100
)

 percentages
## # A tibble: 1 × 4
##   red_percentage amber_percentage green_percentage gold_percentage
##            <dbl>            <dbl>            <dbl>           <dbl>
## 1           32.9             50.5             10.7            5.87
# ggsave(here("figures", "fig2a.pdf"), width = 25, height = 15, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "fig2a.jpg"), width = 25, height = 15, units = "cm", scale = 2, dpi = 800)

Making the CEESAT question groups for result reporting

# Create new categories for specified questions in numerical order
percent_ceesat_score$combined_category <- ifelse(
  grepl("^1\\.1", percent_ceesat_score$question) | grepl("^2\\.1", percent_ceesat_score$question),
  "Study Question",
  ifelse(grepl("^3\\.1", percent_ceesat_score$question) | grepl("^3\\.2", percent_ceesat_score$question),
    "Literature Searching",
    ifelse(grepl("^4\\.1", percent_ceesat_score$question) | grepl("^4\\.2", percent_ceesat_score$question) | grepl("^4\\.3", percent_ceesat_score$question),
      "Literature Screening",
      ifelse(grepl("^5\\.1", percent_ceesat_score$question) | grepl("^5\\.2", percent_ceesat_score$question) | 
             grepl("^6\\.1", percent_ceesat_score$question) | grepl("^6\\.2", percent_ceesat_score$question) | grepl("^6\\.3", percent_ceesat_score$question),
        "Data Extraction", 
        ifelse(grepl("^7", percent_ceesat_score$question), "Data Analysis", 
          ifelse(grepl("^8", percent_ceesat_score$question), "Study Limitations", "Other"))))))

# Group by combined_category and score, then summarize
percent_ceesat_score_grouped <- percent_ceesat_score %>%
  group_by(combined_category, score) %>%
  summarise(total_n = sum(n))

# Calculate the total count for each special category
total_counts <- percent_ceesat_score_grouped %>%
  group_by(combined_category) %>%
  summarise(total_count = sum(total_n))

# Join total counts with grouped data
percent_ceesat_score_grouped <- left_join(percent_ceesat_score_grouped, total_counts, by = "combined_category")

# Add a column for relative percent
percent_ceesat_score_grouped <- percent_ceesat_score_grouped %>%
  mutate(relative_percent = (total_n / total_count) * 100)

print(percent_ceesat_score_grouped)
## # A tibble: 22 × 5
## # Groups:   combined_category [6]
##    combined_category    score total_n total_count relative_percent
##    <chr>                <fct>   <int>       <int>            <dbl>
##  1 Data Analysis        Red        23         249             9.24
##  2 Data Analysis        Amber     192         249            77.1 
##  3 Data Analysis        Green      27         249            10.8 
##  4 Data Analysis        Gold        7         249             2.81
##  5 Data Extraction      Red       184         415            44.3 
##  6 Data Extraction      Amber     130         415            31.3 
##  7 Data Extraction      Green      53         415            12.8 
##  8 Data Extraction      Gold       48         415            11.6 
##  9 Literature Screening Red       113         249            45.4 
## 10 Literature Screening Amber     120         249            48.2 
## # ℹ 12 more rows
# view(percent_ceesat_score_grouped)

Calculating altmetric for each study

# load data
bib_alt <- read_csv(here("data","scopus.csv")) 

# function getAltmetrics(), the only parameter is doi; see example below
getAltmetrics <- function(doi = NULL,
                          foptions = list(),
                           ...) {
    if (!is.null(doi)) doi <- stringr::str_c("doi/", doi)
    identifiers <- purrr::compact(list(doi))
    if (!is.null(identifiers)) {
      ids <- identifiers[[1]]
    }
    base_url <- "http://api.altmetric.com/v1/"
    #request <- httr::GET(paste0(base_url, ids), httr::add_headers("user-agent" = "#rstats rAltmertic package https://github.com/ropensci/rAltmetric"))
    request <- httr::GET(paste0(base_url, ids))
    results <-
      jsonlite::fromJSON(httr::content(request, as = "text"), flatten = TRUE)
    results <- rlist::list.flatten(results)
    class(results) <- "altmetric"
    results
}
altmetric.crawler <- list(NULL)
for (n in 1:length(bib_alt$DOI)) {
 # format altmetric object
  format.Altmetric <- function(altmetric.object) {
  stats <- altmetric.object[grep("^cited", names(altmetric.object))]
  stats <- data.frame(stats, stringsAsFactors = FALSE)
  data.frame(paper_title = altmetric.object$title,
             journal = altmetric.object$journal,
             doi = altmetric.object$doi,
             #subject = altmetric.object$subjects,
             Altmetric.score = altmetric.object$score,
             stats = stats)
}
   # JASON formate
  altmetric.crawler[[n]]  <-  try(list(format.Altmetric(getAltmetrics(doi = bib_alt$DOI[n])))) # https://stackoverflow.com/questions/14059657/how-to-skip-an-error-in-a-loop?rq=1
  
  # create a dataframe function
  altmetric_df <- function(altmetric.object) {
  df <- data.frame(t(unlist(altmetric.object)), stringsAsFactors = FALSE)
  }
  #altmetric.crawler[[n]]  <-  try(list(altmetric_df(getAltmetrics(doi = DOIs[n]))))
  # create a function to summarize Altmetric object
  summary.altmetric <- function(x, ...) {
  if (inherits(x, "altmetric"))  {
string <- "Altmetrics on: \"%s\" with altmetric_id: %s published in %s."
vals   <- c(x$title,  x$altmetric_id, x$journal)
 if("journal" %in% names(x)) {
  cat(do.call(sprintf, as.list(c(string, vals))))
 } else {
   string <- "Altmetrics on: \"%s\" with altmetric_id: %s"
   cat(do.call(sprintf, as.list(c(string, vals))))
 }
  cat("\n")
  stats <- x[grep("^cited", names(x))]
  stats <- data.frame(stats, stringsAsFactors = FALSE)
  print(data.frame(stats = t(stats)))
  }
}
  # crawl
 # altmetric.crawler[[n]] <- try(list(summary.altmetric(getAltmetrics(doi = DOIs[n]))))
}
## Error : lexical error: invalid char in json text.
##                                        Not Found
##                      (right here) ------^
## 
## Error : lexical error: invalid char in json text.
##                                        Not Found
##                      (right here) ------^
## 
## Error : lexical error: invalid char in json text.
##                                        Not Found
##                      (right here) ------^
## 
## Error : lexical error: invalid char in json text.
##                                        Not Found
##                      (right here) ------^
## 
## Error : lexical error: invalid char in json text.
##                                        Not Found
##                      (right here) ------^
## 
## Error : lexical error: invalid char in json text.
##                                        Not Found
##                      (right here) ------^
## 
## Error : lexical error: invalid char in json text.
##                                        Not Found
##                      (right here) ------^
## 
## Error : lexical error: invalid char in json text.
##                                        Not Found
##                      (right here) ------^
## 
## Error : lexical error: invalid char in json text.
##                                        Not Found
##                      (right here) ------^
## 
## Error : lexical error: invalid char in json text.
##                                        Not Found
##                      (right here) ------^
## 
## Error : lexical error: invalid char in json text.
##                                        Not Found
##                      (right here) ------^
## 
## Error : lexical error: invalid char in json text.
##                                        Not Found
##                      (right here) ------^
## 
## Error : lexical error: invalid char in json text.
##                                        Not Found
##                      (right here) ------^
## 
## Error : lexical error: invalid char in json text.
##                                        Not Found
##                      (right here) ------^
# save results from altmetric.crawler and retrieve lists within lists
altmetric.crawler2 <- sapply(altmetric.crawler, function(x) {x})
# retrieve stats
altmetric.summary <- data.frame(paper_title = sapply(altmetric.crawler2, function(x)  ifelse(class(x) == "data.frame",x$paper_title,NA)),
           journal = sapply(altmetric.crawler2, function(x) ifelse(class(x) == "data.frame",x$journal,NA)),
           doi = sapply(altmetric.crawler2, function(x) ifelse(class(x) == "data.frame",x$doi,NA)),
           #subject = sapply(altmetric.crawler2, function(x) ifelse(class(x) == "data.frame",x$subject,NA)),
           Altmetric.score = sapply(altmetric.crawler2, function(x) ifelse(class(x) == "data.frame",x$Altmetric.score,0)),
           policy = sapply(altmetric.crawler2, function(x) ifelse(class(x) == "data.frame",ifelse(!is.null(x$stats.cited_by_policies_count),x$stats.cited_by_policies_count,0),0)),
           patent = sapply(altmetric.crawler2, function(x) ifelse(class(x) == "data.frame",ifelse(!is.null(x$stats.cited_by_patents_count),x$stats.cited_by_patents_count,0),0))
           )
# Adding new columns to bib_alt dataframe
bib_alt <- bib_alt %>%
   mutate(Altmetric.score = altmetric.summary$Altmetric.score, 
          policy = altmetric.summary$policy, 
          patent = altmetric.summary$patent)

# Defining the scoring function
score <- function(x) {
  case_when(
    x == 'Red' ~ 0,
    x == 'Amber' ~ 1,
    x == 'Green' ~ 3,
    x == 'Gold' ~ 4,
    TRUE ~ NA_real_
  )
}
# Apply the scoring function across all columns starting with "CEESAT"
sd <- sd %>%
  mutate(across(starts_with("CEESAT"), score, .names = "points_{.col}"))
# Sum all the points columns to create a 'total_points' column
sd <- sd %>%
  mutate(total_points = rowSums(select(., starts_with("points_")), na.rm = TRUE))

Figure 2b

CEESAT scores for meta-analyses cited in policy documents (left panel) and those not cited in policy documents (right panel).

# Converting policy to binary and dropping NAs
sd_bib_alt_policy <- left_join(sd, pol, join_by("author_year"), multiple = "all")

sd_bib_alt_policy <- sd_bib_alt_policy %>%
  # Ensure only unique author_year entries are kept
  distinct(author_year, .keep_all = TRUE) %>%
  
  # Create a new column categorizing policy presence
  mutate(
    policy_status = case_when(
      is.na(policy_title) ~ "No Policy",   # If missing (NA), classify as "No Policy"
      policy_title == "no policy" ~ "No Policy",  # If explicitly "no policy", classify as "No Policy"
      TRUE ~ "Policy"   # Everything else is considered a policy document
    )
  )

percent_ceesat_score1 <- sd_bib_alt_policy %>%
  filter(!is.na(author_year)) %>%
  select(studies = author_year, policy_status, starts_with("CEE")) %>%
  na.omit() %>%
  pivot_longer(cols = -c(studies, policy_status), names_to = "question", values_to = "score") %>%
  group_by(policy_status, question, score) %>%
  summarise(n = n(), .groups = 'drop') %>%
  mutate(percent = (n/sum(n))*100, 
         across(c(question, score), as.factor),
         question = fct_recode(question, 
           `1.1` = "CEESAT2_1.1",
           `2.1` = "CEESAT2_2.1",
           `3.1` = "CEESAT2_3.1",
           `3.2` = "CEESAT2_3.2",
           `4.1` = "CEESAT2_4.1",
           `4.2` = "CEESAT2_4.2",
           `4.3` = "CEESAT2_4.3",
           `5.1` = "CEESAT2_5.1",
           `5.2` = "CEESAT2_5.2",
           `6.1` = "CEESAT2_6.1",
           `6.2` = "CEESAT2_6.2",
           `6.3` = "CEESAT2_6.3",
           `7.1` = "CEESAT2_7.1",
           `7.2` = "CEESAT2_7.2",
           `7.3` = "CEESAT2_7.3",
           `8.1` = "CEESAT2_8.1"),
         question = factor(question, levels = rev(levels(question))),
         score = factor(score, levels = levels(score)[c(4,1,3,2)]))


fig2b <- ggplot(data = percent_ceesat_score1, aes(x = question, y = percent, fill = score)) +
  geom_col(width = 0.7, position = "fill", color = "black") +
  geom_text(aes(label = n), position = position_fill(vjust = 0.5), size = 7, fontface = "bold") +
  coord_flip() +
  guides(fill = guide_legend(reverse = TRUE)) +
  scale_fill_manual(values = c("#FF0000","#FFD700","#008000", "#DAA520"), name = "Score:") +
  scale_y_continuous(labels = scales::percent) +
  theme(panel.grid.major = element_blank(), 
        panel.grid.minor = element_blank(), 
        panel.background = element_blank(),
        axis.text.y = element_text(size = 20),
        axis.text.x = element_text(size = 20),
        axis.title.x = element_text(size = 25),
        axis.title.y = element_text(size = 25), 
        legend.position = "none",
        strip.text = element_text(size = 20),
        strip.background = element_blank(), 
        plot.tag = element_text(size = 25)) + 
  ylab("Percentage") + 
  xlab("CEESAT Question") +
  facet_wrap(~policy_status) +
  labs(tag = "B")

fig2b

# ggsave(here("figures", "fig2b.pdf"), width = 25, height = 15, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "fig2b.jpg"), width = 25, height = 15, units = "cm", scale = 2, dpi = 800)


policy <- sd_bib_alt_policy$total_points[sd_bib_alt_policy$policy_status == "Policy"]
not_policy <- sd_bib_alt_policy$total_points[sd_bib_alt_policy$policy_status == "No Policy"]


# Create a tibble for policy values
policy_df <- tibble(
  values = policy,
  category = "Policy"
)

# Create a tibble for not_policy values
not_policy_df <- tibble(
  values = not_policy,
  category = "No Policy"
)

# Combine both tibbles into one
policy_combined <- bind_rows(policy_df, not_policy_df)

# View the combined tibble
print(policy_combined)
## # A tibble: 104 × 2
##    values category
##     <dbl> <chr>   
##  1     13 Policy  
##  2     21 Policy  
##  3     21 Policy  
##  4      0 Policy  
##  5     15 Policy  
##  6     17 Policy  
##  7      3 Policy  
##  8     16 Policy  
##  9     17 Policy  
## 10     14 Policy  
## # ℹ 94 more rows
# QQ Plot
qqnorm(policy)
qqline(policy, col = "red")

# QQ Plot
qqnorm(not_policy)
qqline(not_policy, col = "red") 

policy_model <- clm(factor(values) ~ category, data=policy_combined)

summary(policy_model)
## formula: factor(values) ~ category
## data:    policy_combined
## 
##  link  threshold nobs logLik  AIC    niter max.grad cond.H 
##  logit flexible  104  -319.95 705.89 9(3)  1.88e-13 3.6e+03
## 
## Coefficients:
##                Estimate Std. Error z value Pr(>|z|)
## categoryPolicy  0.04169    0.34233   0.122    0.903
## 
## Threshold coefficients:
##       Estimate Std. Error z value
## 0|3   -1.35344    0.29825  -4.538
## 3|4   -1.18322    0.28830  -4.104
## 4|5   -1.12985    0.28550  -3.957
## 5|6   -1.07791    0.28302  -3.809
## 6|7   -1.02728    0.28072  -3.659
## 7|8   -0.88221    0.27484  -3.210
## 8|9   -0.70142    0.26939  -2.604
## 9|10  -0.53123    0.26588  -1.998
## 10|11 -0.44908    0.26478  -1.696
## 11|12 -0.32855    0.26402  -1.244
## 12|13 -0.21044    0.26409  -0.797
## 13|14 -0.13264    0.26434  -0.502
## 14|15  0.02161    0.26450   0.082
## 15|16  0.13709    0.26458   0.518
## 16|17  0.33177    0.26631   1.246
## 17|18  0.61558    0.27217   2.262
## 18|19  0.78808    0.27719   2.843
## 19|20  0.87844    0.28036   3.133
## 20|21  1.07018    0.28876   3.706
## 21|22  1.65535    0.32417   5.106
## 22|23  1.80323    0.33560   5.373
## 23|24  2.05957    0.35928   5.732
## 24|25  2.15742    0.36963   5.837
## 25|26  2.26341    0.38154   5.932
## 26|27  2.37935    0.39567   6.013
## 27|29  2.50760    0.41270   6.076
## 29|30  2.65143    0.43346   6.117
## 30|31  3.00805    0.49400   6.089
## 31|32  3.24108    0.54172   5.983
## 32|37  3.53860    0.61348   5.768
## 37|38  3.95391    0.73682   5.366
## 38|39  4.65680    1.02117   4.560
policy_model_sensitivity <- t.test(policy,not_policy) 

policy_model_sensitivity
## 
##  Welch Two Sample t-test
## 
## data:  policy and not_policy
## t = -0.13057, df = 100.22, p-value = 0.8964
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -4.114662  3.606514
## sample estimates:
## mean of x mean of y 
##  13.42593  13.68000

Figure 2c

Bar plot showing the percentage and total count of bias methodologies used in meta-analyses investigating the impacts of organochlorine pesticides. Note that some meta-analyses may contribute to multiple sections if the study involved the use of multiple bias assessment methodologies.

# Calculate the total count for each category
bias_method_count <- sd %>% 
  separate_rows(bias_assessment_method, sep = ",\\s+") %>% 
  count(bias_assessment_method) %>%
  filter(bias_assessment_method != "NA") %>%
  group_by(bias_assessment_method) %>%
  summarise(n = sum(n))

# Calculate proportion and percentage
bias_method_pct <- bias_method_count %>%
  mutate(proportion = n / 83,
         percentage = proportion * 100)

# Create the bar plot
fig2c <- bias_method_count %>%
  ggplot(aes(x = n, y = reorder(bias_assessment_method, n), 
             fill = ifelse(grepl("Not reported", bias_assessment_method), "#7370b3", "#1b9e77"))) +
  geom_bar(stat = "identity", width = 0.8, alpha = 0.7) +
  geom_text(aes(label = ifelse(n > 1, n, ""), x = n / 2), hjust = 0.5, size = 12, color = "black") +
  geom_text(data = bias_method_pct %>% filter(n > 1), 
            aes(label = paste0("(", round(percentage, 1), "%)"), x = n), 
            hjust = -0.1, size = 12, color = "black", fontface = "bold") +
  scale_fill_identity(guide = "none") +
  scale_x_continuous(expand = c(0, 0), limits = c(0, max(bias_method_count$n) * 1.3)) +
  labs(title = "Publication Bias Count", x = NULL, y = NULL, tag = "C", size = 30) +
  organochlorTHEME()

fig2c

# ggsave(here("figures", "fig2c.pdf"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "fig2c.jpg"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)

Figure 2d

Bar plot showing the percentage and total count of heterogeneity assessment methods used in meta-analyses investigating the impacts of organochlorine pesticides. Note that some meta-analyses may contribute to multiple sections if the study involved multiple heterogeneity assessments. Percentage is showing the proportion of studies.

# Figure 3b: Heterogeneity Assessment Methods
heterogeneity_count <- sd %>% 
  separate_rows(heterogeneity_assessment_method, sep = ",\\s+") %>% 
  count(heterogeneity_assessment_method) %>%
  filter(heterogeneity_assessment_method != "NA") %>%
  group_by(heterogeneity_assessment_method) %>%
  summarise(n = sum(n))

heterogeneity_pct <- heterogeneity_count %>%
  mutate(proportion = n / 83,
         percentage = proportion * 100)

fig2d <- heterogeneity_count %>%
  ggplot(aes(x = n, y = reorder(heterogeneity_assessment_method, n), 
             fill = ifelse(grepl("Not reported", heterogeneity_assessment_method), "#7370b3", "#1b9e77"))) +
  geom_bar(stat = "identity", width = 0.8, alpha = 0.7) +
  geom_text(aes(label = ifelse(n > 1, n, ""), x = n / 2), hjust = 0.5, size = 12, color = "black") +
  geom_text(data = heterogeneity_pct %>% filter(n > 1), 
            aes(label = paste0("(", round(percentage, 1), "%)"), x = n), 
            hjust = -0.1, size = 12, color = "black", fontface = "bold") +
  scale_fill_identity(guide = "none") +
  scale_x_continuous(expand = c(0, 0), limits = c(0, max(heterogeneity_count$n) * 1.3)) +
  labs(title = "Heterogeneity Count", x = NULL, y = NULL, tag = "D", size = 30) +
  organochlorTHEME()

fig2d

# ggsave(here("figures", "fig2d.pdf"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "fig2d.jpg"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)

Figure 2e

Bar plot showing the percentage and total count of sensitivity analyses conducted in meta-analyses investigating the impacts of organochlorine pesticides. Note that some meta-analyses may contribute to multiple sections if the study involved multiple sensitivity analyses.

# Figure 3c: Sensitivity Analysis Methods
sensitivity_count <- sd %>% 
  separate_rows(sensitivity_analysis_method, sep = ",\\s+") %>% 
  count(sensitivity_analysis_method) %>%
  filter(sensitivity_analysis_method != "NA") %>%
  group_by(sensitivity_analysis_method) %>%
  summarise(n = sum(n))

sensitivity_pct <- sensitivity_count %>%
  mutate(proportion = n / 83,
         percentage = proportion * 100)

fig2e <- sensitivity_count %>%
  ggplot(aes(x = n, y = reorder(sensitivity_analysis_method, n), 
             fill = ifelse(grepl("Not reported", sensitivity_analysis_method), "#7370b3", "#1b9e77"))) +
  geom_bar(stat = "identity", width = 0.8, alpha = 0.7) +
  geom_text(aes(label = ifelse(n > 1, n, ""), x = n / 2), hjust = 0.5, size = 12, color = "black") +
  geom_text(data = sensitivity_pct %>% filter(n > 1), 
            aes(label = paste0("(", round(percentage, 1), "%)"), x = n), 
            hjust = -0.1, size = 12, color = "black", fontface = "bold") +
  scale_fill_identity(guide = "none") +
  scale_x_continuous(expand = c(0, 0), limits = c(0, max(sensitivity_count$n) * 1.3)) +
  labs(title = "Sensitivity Analysis Count", x = NULL, y = NULL, tag = "E", size = 30) +
  organochlorTHEME()

fig2e

# ggsave(here("figures", "fig2e.pdf"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "fig2e.jpg"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)

Figure 2f

Bar plot showing the percentage and total count of reporting guidelines used in meta-analyses investigating the impacts of organochlorine pesticides. Note that some meta-analyses may contribute to multiple sections if the study involved the use of multiple reporting guidelines.

# Figure 3d: Reporting Guidelines
reporting_guide_count <- sd %>% 
  separate_rows(reporting_standards_type, sep = ",\\s+") %>% 
  count(reporting_standards_type) %>%
  filter(reporting_standards_type != "NA") %>%
  mutate(reporting_standards_type = ifelse(n < 3, "Other Guidelines", as.character(reporting_standards_type))) %>%
  group_by(reporting_standards_type) %>%
  summarise(n = sum(n))

reporting_guide_pct <- reporting_guide_count %>%
  mutate(proportion = n / 83,
         percentage = proportion * 100)

fig2f <- reporting_guide_count %>%
  ggplot(aes(x = n, y = reorder(reporting_standards_type, n), 
             fill = ifelse(grepl("Not reported", reporting_standards_type), "#7370b3", "#1b9e77"))) +
  geom_bar(stat = "identity", width = 0.8, alpha = 0.7) +
  geom_text(aes(label = ifelse(n > 1, n, ""), x = n / 2), hjust = 0.5, size = 12, color = "black") +
  geom_text(data = reporting_guide_pct %>% filter(n > 1), 
            aes(label = paste0("(", round(percentage, 0), "%)"), x = n), 
            hjust = -0.1, size = 12, color = "black", fontface = "bold") +
  scale_fill_identity(guide = "none") +
  scale_x_continuous(expand = c(0, 0), limits = c(0, max(reporting_guide_count$n) * 1.3)) +
  labs(title = "Reporting Guideline Count", x = NULL, y = NULL, tag = "F", size = 30) +
  
  organochlorTHEME()

fig2f

# ggsave(here("figures", "fig2f.pdf"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "fig2f.jpg"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)

CEESAT reporitng guideline

CEESAT scores for meta-analyses referencing a reporting guideline (right panel) and those not referencing a reporting guideline (left panel).

sd_bib_alt_guideline <- sd %>% 
  mutate(binary_guideline = if_else(reporting_standards_type == "Not reported", "Not reported", "Reported")) %>% 
    drop_na(binary_guideline, total_points)

percent_ceesat_score2 <- sd_bib_alt_guideline %>%
  filter(!is.na(author_year)) %>%
  select(studies = author_year, binary_guideline, starts_with("CEE")) %>%
  na.omit() %>%
  pivot_longer(cols = -c(studies, binary_guideline), names_to = "question", values_to = "score") %>%
  group_by(binary_guideline, question, score) %>%
  summarise(n = n(), .groups = 'drop') %>%
  mutate(percent = (n/sum(n))*100, 
         across(c(question, score), as.factor),
         question = fct_recode(question, 
           `1.1` = "CEESAT2_1.1",
           `2.1` = "CEESAT2_2.1",
           `3.1` = "CEESAT2_3.1",
           `3.2` = "CEESAT2_3.2",
           `4.1` = "CEESAT2_4.1",
           `4.2` = "CEESAT2_4.2",
           `4.3` = "CEESAT2_4.3",
           `5.1` = "CEESAT2_5.1",
           `5.2` = "CEESAT2_5.2",
           `6.1` = "CEESAT2_6.1",
           `6.2` = "CEESAT2_6.2",
           `6.3` = "CEESAT2_6.3",
           `7.1` = "CEESAT2_7.1",
           `7.2` = "CEESAT2_7.2",
           `7.3` = "CEESAT2_7.3",
           `8.1` = "CEESAT2_8.1"),
         question = factor(question, levels = rev(levels(question))),
         score = factor(score, levels = levels(score)[c(4,1,3,2)]))

ceesat_report <- ggplot(data = percent_ceesat_score2, aes(x = question, y = percent, fill = score)) +
  geom_col(width = 0.7, position = "fill", color = "black") +
  geom_text(aes(label = n), position = position_fill(vjust = 0.5), size = 7, fontface = "bold") +
  coord_flip() +
  guides(fill = guide_legend(reverse = TRUE)) +
  scale_fill_manual(values = c("#FF0000","#FFD700","#008000", "#DAA520"), name = "Score:") +
  scale_y_continuous(labels = scales::percent) +
  theme(panel.grid.major = element_blank(), 
        panel.grid.minor = element_blank(), 
        panel.background = element_blank(),
        axis.text.y = element_text(size = 20),
        axis.text.x = element_text(size = 20),
        axis.title.x = element_text(size = 25),
        axis.title.y = element_text(size = 25), 
        legend.position = "top",  
        legend.justification = "left",  
        legend.direction = "horizontal",
        legend.box = "horizontal",  
        legend.box.just = "left",  
        legend.title.align = 0.5,  
        legend.key.size = unit(1, "cm"),  
        legend.title = element_text(size =25),
        legend.text = element_text(size = 25),  
        strip.text = element_text(size = 20),
        strip.background = element_blank()) +  
  ylab("Percentage") + 
  xlab("CEESAT Question") +
  facet_wrap(~binary_guideline) 

ceesat_report

# ggsave(here("figures", "ceesat_report.pdf"), width = 25, height = 15, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "ceesat_report.jpg"), width = 25, height = 15, units = "cm", scale = 2, dpi = 800)

guideline <- sd_bib_alt_guideline$total_points[sd_bib_alt_guideline$binary_guideline == "Reported"]
no_guideline <- sd_bib_alt_guideline$total_points[sd_bib_alt_guideline$binary_guideline == "Not reported"]


# Create a tibble for policy values
guideline_df <- tibble(
  values = guideline,
  category = "Cited Guideline"
)

# Create a tibble for not_policy values
no_guideline_df <- tibble(
  values = no_guideline,
  category = "No Guideline"
)

# Combine both tibbles into one
guideline_combined <- bind_rows(guideline_df, no_guideline_df)

# View the combined tibble
print(guideline_combined)
## # A tibble: 79 × 2
##    values category       
##     <dbl> <chr>          
##  1      7 Cited Guideline
##  2     11 Cited Guideline
##  3     17 Cited Guideline
##  4     21 Cited Guideline
##  5     20 Cited Guideline
##  6     16 Cited Guideline
##  7     31 Cited Guideline
##  8     15 Cited Guideline
##  9     37 Cited Guideline
## 10     16 Cited Guideline
## # ℹ 69 more rows
guideline_model <- clm(factor(values) ~ category, data=guideline_combined)

summary(guideline_model)
## formula: factor(values) ~ category
## data:    guideline_combined
## 
##  link  threshold nobs logLik  AIC    niter max.grad cond.H 
##  logit flexible  79   -239.91 543.82 7(0)  1.32e-10 1.1e+03
## 
## Coefficients:
##                      Estimate Std. Error z value Pr(>|z|)    
## categoryNo Guideline  -2.4120     0.4656   -5.18 2.22e-07 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Threshold coefficients:
##       Estimate Std. Error z value
## 3|4    -5.4661     0.8159  -6.699
## 4|5    -5.0368     0.7056  -7.138
## 5|6    -4.7247     0.6429  -7.348
## 6|7    -4.4765     0.6018  -7.439
## 7|8    -3.9375     0.5328  -7.391
## 8|9    -3.5474     0.4963  -7.148
## 9|10   -3.1240     0.4646  -6.724
## 10|11  -2.9399     0.4524  -6.498
## 11|12  -2.6925     0.4375  -6.154
## 12|13  -2.4601     0.4241  -5.801
## 13|14  -2.3063     0.4149  -5.559
## 14|15  -2.0034     0.3959  -5.060
## 15|16  -1.7814     0.3818  -4.666
## 16|17  -1.4169     0.3588  -3.949
## 17|18  -0.9985     0.3371  -2.963
## 18|19  -0.7251     0.3270  -2.218
## 19|20  -0.5890     0.3235  -1.820
## 20|21  -0.3875     0.3212  -1.206
## 21|22   0.4028     0.3269   1.232
## 22|23   0.5959     0.3335   1.787
## 23|24   0.9087     0.3520   2.582
## 24|25   1.0256     0.3608   2.842
## 25|26   1.1529     0.3712   3.106
## 26|27   1.2894     0.3842   3.356
## 27|29   1.4373     0.4003   3.591
## 29|30   1.6001     0.4206   3.804
## 30|31   1.9927     0.4816   4.138
## 31|32   2.2427     0.5301   4.231
## 32|37   2.5566     0.6028   4.241
## 37|38   2.9876     0.7275   4.107
## 38|39   3.7056     1.0141   3.654
t.test(guideline,no_guideline)
## 
##  Welch Two Sample t-test
## 
## data:  guideline and no_guideline
## t = 6.1128, df = 68.538, p-value = 5.269e-08
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##   6.091412 11.994595
## sample estimates:
## mean of x mean of y 
##  21.92105  12.87805

Scatter plot policy & quality

Scatter plot showing the relationship between the quantity of times cited in a policy document and total CEESAT score

# Create the plot 
policy_quality <- sd_bib_alt_policy %>%
 # filter(total_points != 0, policy != 0) %>% 
  ggplot(aes(x = total_points, y = policy)) +
  geom_point(color = "#1b9e77", alpha = 0.8, size = 8) +
  geom_smooth(method = lm, se = TRUE, color = "red") +
  labs(x = "Total CEESAT score", y = "Policy Count") +
  theme_minimal() +
  theme(panel.grid.major.y = element_blank(),
        axis.line.y = element_blank(),
        axis.ticks.y = element_blank(),
        axis.text.x = element_text(size = 25),
        axis.text.y = element_text(size = 25),
        axis.title.x = element_text(size = 30),
        axis.title.y = element_text(size = 30),
        plot.title = element_blank())

policy_quality
## Error in `geom_point()`:
## ! Problem while computing aesthetics.
## ℹ Error occurred in the 1st layer.
## Caused by error in `check_aesthetics()`:
## ! Aesthetics must be either length 1 or the same as the data (104).
## ✖ Fix the following mappings: `y`.
# ggsave(here("figures", "policy_quality.pdf"), width = 25, height = 15, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "policy_quality.jpg"), width = 25, height = 15, units = "cm", scale = 2, dpi = 800)

Box ceesat scores

Box and violin plot showing the distribution of CEESAT scores for studies cited in policy documents and studies not cited in policy documents

box_ceesat <- policy_combined %>%
  ggplot(aes(x = category, y = values)) +
  geom_violin(fill = "#1b9e77", alpha =0.2, color = NA, trim = FALSE) +
  geom_boxplot(width = 0.05, fill = "white", color = "#1b9e77", outlier.shape = NA) +
  geom_jitter(width = 0.1, height = 0.05, color = "#1b9e77", alpha = 0.8, size = 6) +
  scale_y_continuous(limits = c(0, max(sd$total_points))) +
  labs( x = "Policy", y = "Total CEESAT Score") +
  theme_minimal() +
  theme(panel.grid.major.y = element_blank(),
        axis.line.y = element_blank(),
        axis.ticks.y = element_blank(),
        axis.text.x = element_text(size = 25),
        axis.text.y = element_text(size = 25),
        axis.title.x = element_text(size = 30),
        axis.title.y = element_text(size = 30),
        plot.title = element_blank())

box_ceesat

# ggsave(here("figures", "box_ceesat.pdf"), width = 25, height = 15, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "box_ceesat.jpg"), width = 25, height = 15, units = "cm", scale = 2, dpi = 800)

Alluvial plot for bias assessment

Alluvial plot showing the relationship between the Journal Citation Report Category and bias assessment method.

# Data Transformation 
bias_assessment_alluvial <- sd %>% 
    separate_rows(bias_assessment_method, sep = ",\\s+") %>%
    separate_rows(Journal_Category_Allocated_Broad, sep = "/\\s+") %>% 
    filter(!is.na(bias_assessment_method)) %>%
    group_by(Journal_Category_Allocated_Broad, bias_assessment_method) %>% 
    count(bias_assessment_method, Journal_Category_Allocated_Broad) %>% 
    summarise(freq = n(), .groups = 'drop') %>% 
    group_by(bias_assessment_method)

# Create the Alluvial plot
alluvial_bias <- bias_assessment_alluvial %>% 
  ggplot(aes(y = freq ,axis1 = Journal_Category_Allocated_Broad, axis2 = bias_assessment_method)) +
  scale_x_discrete(limits = c("Journal Citation Category", "Bias Assessment"), expand = c(.05, .05)) +
  xlab("Variables") +
  geom_alluvium(aes(fill = Journal_Category_Allocated_Broad)) +
  geom_stratum(width = 1/3.5, fill = "white", color = "black") +
  geom_text(stat = "stratum", aes(label = after_stat(stratum)), size = 6) +
  labs(x= "Variables", y = "Frequency", fill = "Journal Category Allocated") +
  scale_fill_brewer(palette = "Dark2") +
  organochlorTHEME() 

alluvial_bias

# ggsave(here("figures", "alluvial_bias.pdf"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "alluvial_bias.jpg"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)

Alluvial plot for Heterogeneity

Alluvial plot showing the relationship between the Journal Citation Report Category and heterogeneity assessment method.

# Data Transformation 
heterogeneity_alluvial <- sd %>% 
    separate_rows(heterogeneity_assessment_method, sep = ",\\s+") %>%
    separate_rows(Journal_Category_Allocated_Broad, sep = "/\\s+") %>% 
    filter(!is.na(heterogeneity_assessment_method)) %>%
    group_by(Journal_Category_Allocated_Broad, heterogeneity_assessment_method) %>% 
    count(heterogeneity_assessment_method, Journal_Category_Allocated_Broad) %>% 
    summarise(freq = n(), .groups = 'drop') %>% 
    group_by(heterogeneity_assessment_method) 

# Create the Alluvial plot
alluvial_het <- heterogeneity_alluvial %>% 
ggplot(aes(y = freq ,axis1 = Journal_Category_Allocated_Broad, axis2 = heterogeneity_assessment_method)) +
  scale_x_discrete(limits = c("Journal Citation Category", "Heterogeneity"), expand = c(.05, .05)) +
  xlab("Variables") +
  geom_alluvium(aes(fill = Journal_Category_Allocated_Broad)) +
  geom_stratum(width = 1/4.5, fill = "white", color = "black") +
  geom_text(stat = "stratum", aes(label = after_stat(stratum)), size = 6) +
  labs(x= "Variables", y = "Frequency", fill = "Journal Category Allocated") +
  scale_fill_brewer(palette = "Dark2") +
  organochlorTHEME() 

alluvial_het

# ggsave(here("figures", "alluvial_het.pdf"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "alluvial_het.jpg"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)

Figure s10

Alluvial plot showing the relationship between the Journal Citation Report Category and sensitivity analysis.

# Data Transformation 
sensitivity_analysis_alluvial <- sd %>% 
    separate_rows(sensitivity_analysis_method, sep = ",\\s+") %>%
    separate_rows(Journal_Category_Allocated_Broad, sep = "/\\s+") %>% 
    filter(!is.na(sensitivity_analysis_method)) %>%
    group_by(Journal_Category_Allocated_Broad, sensitivity_analysis_method) %>% 
    count(sensitivity_analysis_method, Journal_Category_Allocated_Broad) %>% 
    summarise(freq = n(), .groups = 'drop') %>% 
    group_by(sensitivity_analysis_method)

# Create the Alluvial plot
alluvial_sens <- sensitivity_analysis_alluvial %>% 
ggplot(aes(y = freq ,axis1 = Journal_Category_Allocated_Broad, axis2 = sensitivity_analysis_method)) +
  scale_x_discrete(limits = c("Journal Citation Category", "Sensitivity Analysis"), expand = c(.05, .05)) +
  xlab("Variables") +
  geom_alluvium(aes(fill = Journal_Category_Allocated_Broad)) +
  geom_stratum(width = 1/4, fill = "white", color = "black") +
  geom_text(stat = "stratum", aes(label = after_stat(stratum)), size = 5) +
  labs(x= "Variables", y = "Frequency", fill = "Journal Category Allocated") +
  scale_fill_brewer(palette = "Dark2") +
  organochlorTHEME() 

alluvial_sens

# ggsave(here("figures", "alluvial_sens.pdf"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "alluvial_sens.jpg"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)

Alluvial plot for reporting guideline

An alluvial plot showing the relationship between the Journal Citation Report Category and reporting guideline used

# Data Transformation 
reporting_standards_alluvial <- sd %>% 
    separate_rows(reporting_standards_type, sep = ",\\s+") %>%
    separate_rows(Journal_Category_Allocated_Broad, sep = "/\\s+") %>%
    filter(!grepl("no category found", Journal_Category_Allocated_Broad, ignore.case = TRUE)) %>% 
    filter(!is.na(reporting_standards_type)) %>%
    group_by(Journal_Category_Allocated_Broad, reporting_standards_type) %>% 
    count(reporting_standards_type, Journal_Category_Allocated_Broad) %>% 
    summarise(freq = n(), .groups = 'drop') %>% 
    group_by(reporting_standards_type)

# Create the Alluvial plot
alluvial_report <- reporting_standards_alluvial %>% 
ggplot( aes(y = freq ,axis1 = Journal_Category_Allocated_Broad, axis2 = reporting_standards_type)) +
  scale_x_discrete(limits = c("Journal Citation Category", "Reporting Standards Type"), expand = c(.05, .05)) +
  xlab("Variables") +
  geom_alluvium(aes(fill = Journal_Category_Allocated_Broad)) +
  geom_stratum(width = 1/3.5, fill = "white", color = "black") +
  labs(x= "Variables", y = "Frequency", fill = "Journal Category Allocated") +
  geom_text(stat = "stratum", aes(label = after_stat(stratum)), size = 6) +
    scale_fill_brewer(palette = "Dark2") +
  organochlorTHEME() 

alluvial_report

# ggsave(here("figures", "alluvial_report.pdf"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "alluvial_report.jpg"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)

Database bar plot

Bar plot showing the percentage and total count of scientific literature databases used in meta-analyses investigating the impacts of organochlorine pesticides. Note that some meta-analyses may contribute to multiple sections if the study involved multiple scientific literature databases. The “Other databases” category includes all databases with a count of 3 or less. Percentage is showing the proportion of studies.

# Calculate the total count for each category
database_count <- sd %>% 
  separate_rows(database_search, sep = ",\\s+") %>% 
  count(database_search) %>% 
  filter(database_search != "NA") %>% 
  arrange(desc(n)) %>% 
  mutate(database_search = ifelse(n<= 3, "Other databases", as.character(database_search))) %>% 
    group_by(database_search) %>%
  summarise(n = sum(n))

# Calculate proportion and percentage for each category
database_pct <- database_count %>%
  mutate(proportion = n / 83, # 83 is number of studies assessed for CEESAT
         percentage = proportion * 100)

# Create the count plot
database_bar <- database_count %>%
  ggplot(aes(x = n, y = reorder(database_search, n), fill = "#1b9e77")) +
  geom_bar(stat = "identity", width = 0.8 , alpha = 0.7) +
  geom_text(aes(label = n, x = n / 2, y = reorder(database_search, n)), hjust = 0.5, size = 12, color = "black") +
  geom_text(data = database_pct, aes(label = paste0("(", round(percentage, 1), "%)"), x = n), 
            hjust = -0.1, size = 12, color = "black", fontface = "bold") +
  scale_fill_identity(guide = "none") +
  scale_x_continuous(expand = c(0, 0), limits = c(0, max(database_count$n)*1.3)) +
  labs(title = NULL, x = NULL, y = NULL) +
  organochlorTHEME() 

database_bar

# ggsave(here("figures", "database_bar.pdf"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "database_bar.jpg"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)

Alluvial plot for literature database

Alluvial plot showing the relationship between the Journal Citation Report Category and the scientific literature database used. Filtered for scientific literature database counts greater than or equal to 3.

# Rename Environmental Science
sd <- sd %>%
  mutate(Journal_Category_Allocated_Broad = str_replace(Journal_Category_Allocated_Broad, "Environmental Science", "Environmental\nScience"))

# Data Transformation 
database_alluvial <- sd %>% 
    separate_rows(database_search, sep = ",\\s+") %>%
    group_by(Journal_Category_Allocated_Broad, database_search) %>% 
    count(database_search, Journal_Category_Allocated_Broad) %>% 
    summarise(freq = n(), .groups = 'drop') %>% 
    group_by(database_search) %>% 
    filter(sum(freq) >= 3) %>% 
    filter(database_search != "NA")

# Create the Alluvial plot
alluvial_database <- database_alluvial %>% 
ggplot(aes(y = freq ,axis1 = Journal_Category_Allocated_Broad, axis2 = database_search)) +
  scale_x_discrete(limits = c("Journal Citation Report", "Database Search"), expand = c(.05, .05)) +
  xlab("Variables") +
  ylab("Frequency") +
  geom_alluvium(aes(fill = Journal_Category_Allocated_Broad)) +
  geom_stratum(width = 1/4.5, fill = "white", color = "black") +
  geom_text(stat = "stratum", aes(label = after_stat(stratum)), size = 6) +
  labs(x= "Variables", y = "Frequency", fill = "Journal Category Allocated") +
  scale_fill_brewer(palette = "Dark2") +
  organochlorTHEME() 

alluvial_database

# ggsave(here("figures", "alluvial_database.pdf"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "alluvial_database.jpg"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)

Software bar plot

Bar plot showing the percentage and total count of software for analysis used in meta-analyses investigating the impacts of organochlorine pesticides. Note that some meta-analyses may contribute to multiple sections if the study involved multiple software. Percentage is showing the proportion of studies.

# Calculate the total count for each category
software_count <- sd %>%
  separate_rows(software_analysis, sep = ",\\s+") %>%
  mutate(software_analysis = ifelse(grepl("comprehensive meta-analysis", software_analysis), "CMAS", software_analysis)) %>%
  count(software_analysis) %>%
  filter(software_analysis != "NA") %>%
  arrange(desc(n)) %>%
  mutate(software_analysis = ifelse(n < 2, "Other Software", as.character(software_analysis))) %>%
  group_by(software_analysis) %>%
  summarise(n = sum(n))

# Calculate proportion and percentage for each category
software_pct <- software_count %>%
  mutate(proportion = n / 83,
         percentage = proportion * 100)

# Create the count plot
software_bar <- software_count %>%
  ggplot(aes(x = n, y = reorder(software_analysis, n), fill = "#1b9e77")) +
  geom_bar(stat = "identity", width = 0.8 , alpha = 0.7) +
  geom_text(aes(label = n, x = n / 2, y = reorder(software_analysis, n)), hjust = 0.5, size = 12, color = "black") +
  geom_text(data = software_pct, aes(label = paste0("(", round(percentage, 1), "%)"), x = n), 
            hjust = -0.1, size = 12, color = "black", fontface = "bold") +
  scale_fill_identity(guide = "none") +
  scale_x_continuous(expand = c(0, 0), limits = c(0, max(software_count$n)*1.3)) +
  labs(title = NULL, x = NULL, y = NULL) +
  organochlorTHEME() 

software_bar

# ggsave(here("figures", "software_bar.pdf"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "software_bar.jpg"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)

Alluvial plot for software

Alluvial plot showing the relationship between the Journal Citation Report Category and the software used for analysis.

# Data Transformation 
software_analysis_alluvial <- sd %>% 
    separate_rows(software_analysis, sep = ",\\s+") %>%
    separate_rows(Journal_Category_Allocated_Broad, sep = "/\\s+") %>% 
  mutate(software_analysis = ifelse(grepl("comprehensive meta-analysis", software_analysis), "CMAS", software_analysis)) %>%
  mutate(software_analysis = ifelse(grepl("not reported", software_analysis), "no software reported", software_analysis))  %>% 
    filter(!is.na(software_analysis)) %>%
    group_by(Journal_Category_Allocated_Broad, software_analysis) %>% 
    count(software_analysis, Journal_Category_Allocated_Broad) %>% 
    summarise(freq = n(), .groups = 'drop') %>% 
    group_by(software_analysis)

# Create the Alluvial plot for Software Analysis
alluvial_software <- software_analysis_alluvial %>% 
  ggplot(aes(y = freq ,axis1 = Journal_Category_Allocated_Broad, axis2 = software_analysis)) +
  scale_x_discrete(limits = c("Journal Citation Category", "Software Analysis"), expand = c(.05, .05)) +
  xlab("Variables") +
  geom_alluvium(aes(fill = Journal_Category_Allocated_Broad)) +
  geom_stratum(width = 1/4, fill = "white", color = "black") +
  geom_text(stat = "stratum", aes(label = after_stat(stratum)), size = 6) +
  labs(x= "Variables", y = "Frequency", fill = "Journal Category Allocated") +
  scale_fill_brewer(palette = "Dark2") +
  organochlorTHEME() 

alluvial_software

# ggsave(here("figures", "alluvial_software.pdf"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "alluvial_software.jpg"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)

Effect size bar

Bar plot showing the percentage and total count of effect size calculation types used in meta-analyses investigating the impacts of organochlorine pesticides. Note that some meta-analyses may contribute to multiple sections if the study involved multiple effect size calculations. The “Other effect sizes” category includes all effect sizes with a count of 2 or less. Percentage is showing the proportion of studies.

# Calculate the total count for each category
effectsize_count <- sd %>% 
  separate_rows(effect_size, sep = ",\\s+") %>% 
  count(effect_size) %>%
  filter(effect_size != "NA") %>%
  mutate(effect_size = ifelse(n<= 2, "Other effect size", as.character(effect_size))) %>% 
  group_by(effect_size) %>%
  summarise(n = sum(n))

# Calculate proportion and percentage for each category
effectsize_pct <- effectsize_count %>%
  mutate(proportion = n / 83,
         percentage = proportion * 100)

# Create the count plot
effect_bar <-  effectsize_count %>%
  ggplot(aes(x = n, y = reorder(effect_size, n), fill = "#1b9e77")) +
  geom_bar(stat = "identity", width = 0.8 , alpha = 0.7) +
  geom_text(aes(label = n, x = n / 2, y = reorder(effect_size, n)), hjust = 0.5, size = 12, color = "black") +
  geom_text(data = effectsize_pct, aes(label = paste0("(", round(percentage, 1), "%)"), x = n), 
            hjust = -0.1, size = 12, color = "black", fontface = "bold") +
  scale_fill_identity(guide = "none") +
  scale_x_continuous(expand = c(0, 0), limits = c(0, max(effectsize_count$n)*1.3)) +
  labs(title = NULL, x = NULL, y = NULL) +
  organochlorTHEME() 

effect_bar

# ggsave(here("figures", "effect_bar.pdf"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "effect_bar.jpg"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)

Alluvial plot for effect size estimates

Alluvial plot showing the relationship between the Journal Citation Report Category and the effect size used. Filtered for scientific literature database counts greater than or equal to 3.

# Data Transformation 
effectsize_alluvial <- sd %>% 
    separate_rows(effect_size, sep = ",\\s+") %>%
    separate_rows(Journal_Category_Allocated_Broad, sep = "/\\s+") %>% 
    filter(!grepl("no category found", Journal_Category_Allocated_Broad, ignore.case = TRUE)) %>% 
    filter(!is.na(effect_size)) %>%
    group_by(Journal_Category_Allocated_Broad, effect_size) %>% 
    count(effect_size, Journal_Category_Allocated_Broad) %>% 
    summarise(freq = n(), .groups = 'drop') %>% 
    group_by(effect_size) 


# Create the Alluvial plot
alluvial_effect <- effectsize_alluvial %>% 
ggplot(aes(y = freq ,axis1 = Journal_Category_Allocated_Broad, axis2 = effect_size)) +
  scale_x_discrete(limits = c("Journal Citation Category", "Effect Size"), expand = c(.05, .05)) +
  xlab("Variables") +
  geom_alluvium(aes(fill = Journal_Category_Allocated_Broad)) +
  geom_stratum(width = 1/2.5, fill = "white", color = "black") +
  geom_text(stat = "stratum", aes(label = after_stat(stratum)), size = 5) +
  theme_minimal() +
  labs(x= "Variables", y = "Frequency", fill = "Journal Category Allocated") +
  scale_fill_brewer(palette = "Dark2") +
  organochlorTHEME() 
  
alluvial_effect

# ggsave(here("figures", "alluvial_effect.pdf"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "alluvial_effect.jpg"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)

Bar plot for visualisation method

Bar plot showing the percentage and total count of visualization methods used in meta-analyses investigating the impacts of organochlorine pesticides. Note that some meta-analyses may contribute to multiple sections if the study involved the use of multiple visualization methods.

# Calculate the total count for each category
visualization_count <- sd %>% 
  separate_rows(visualization_method, sep = ",\\s+") %>% 
  count(visualization_method) %>%
  filter(visualization_method != "NA") %>%
    group_by(visualization_method) %>%
  summarise(n = sum(n))

# Calculate proportion and percentage for each category
visualization_pct <- visualization_count %>%
  mutate(proportion = n / 83,
         percentage = proportion * 100)

# Create the count plot
bar_vis <- visualization_count %>%
  ggplot(aes(x = n, y = reorder(visualization_method, n), fill = ifelse(grepl("Not reported", visualization_method), "#7370b3", "#1b9e77"))) +
  geom_bar(stat = "identity", width = 0.8 , alpha = 0.7) +
  geom_text(aes(label = n, x = n / 2, y = reorder(visualization_method, n)), hjust = 0.5, size = 12, color = "black") +
  geom_text(data = visualization_pct, aes(label = paste0("(", round(percentage, 0), "%)"), x = n), 
            hjust = -0.1, size = 12, color = "black", fontface = "bold") +
  scale_fill_identity(guide = "none") +
  scale_x_continuous(expand = c(0, 0), limits = c(0, max(visualization_count$n)*1.3)) +
  labs(title = NULL, x = NULL, y = NULL) +
  organochlorTHEME() 

bar_vis

# ggsave(here("figures", "bar_vis.pdf"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "bar_vis.jpg"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)

Alluvial plot for visualisation method

Alluvial plot showing the relationship between the Journal Citation Report Category and visualization method.

# Data Transformation 
visualization_alluvial <- sd %>% 
    separate_rows(visualization_method, sep = ",\\s+") %>%
    filter(!is.na(visualization_method)) %>%
    separate_rows(Journal_Category_Allocated_Broad, sep = "/\\s+") %>%
    group_by(Journal_Category_Allocated_Broad, visualization_method) %>% 
    count(visualization_method, Journal_Category_Allocated_Broad) %>% 
    summarise(freq = n(), .groups = 'drop') %>% 
    group_by(visualization_method) 


# Create the Alluvial plot
alluvial_vis <- visualization_alluvial %>% 
ggplot(aes(y = freq ,axis1 = Journal_Category_Allocated_Broad, axis2 = visualization_method)) +
  scale_x_discrete(limits = c("Journal Citation Report Category", "ROB Assessment Method"), expand = c(.05, .05)) +
  xlab("Variables") +
  geom_alluvium(aes(fill = Journal_Category_Allocated_Broad)) +
  geom_stratum(width = 1/4, fill = "white", color = "black") +
  geom_text(stat = "stratum", aes(label = after_stat(stratum)), size = 6) +
  labs(x= "Variables", y = "Frequency", fill = "Journal Category Allocated") +
  scale_fill_brewer(palette = "Dark2") +
  organochlorTHEME() 

alluvial_vis

# ggsave(here("figures", "alluvial_vis.pdf"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "alluvial_vis.jpg"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)

Bar plot for risk of bias

Bar plot showing the percentage and total count of risk of bias tests used in meta-analyses investigating the impacts of organochlorine pesticides. Note that some meta-analyses may contribute to multiple sections if the study involved the use of multiple risk of bias tests.

# Calculate the total count for each category
rob_method_count <- sd %>% 
  separate_rows(rob_assessment_method, sep = ",\\s+") %>% 
  count(rob_assessment_method) %>%
  filter(rob_assessment_method != "NA") %>%
  mutate(rob_assessment_method = ifelse(n <= 2, "Other ROB tool", as.character(rob_assessment_method))) %>% 
  mutate(rob_assessment_method = ifelse(grepl("Newcastle Ottawa scale", rob_assessment_method), 
                                        "Newcastle Ottawa\nscale", rob_assessment_method)) %>%
  group_by(rob_assessment_method) %>%
  summarise(n = sum(n))

# Calculate proportion and percentage for each category
rob_method_pct <- rob_method_count %>%
  mutate(proportion = n / 83,
         percentage = proportion * 100)

# Create the count plot
bar_risk_of_bias <- rob_method_count %>%
  ggplot(aes(x = n, y = reorder(rob_assessment_method, n), 
             fill = ifelse(grepl("Not reported", rob_assessment_method), "#7370b3", "#1b9e77"))) +
  geom_bar(stat = "identity", width = 0.8 , alpha = 0.7) +
  geom_text(aes(label = n, x = n/2, y = reorder(rob_assessment_method, n)), 
            hjust = 0.5, size = 12, color = "black") +
  geom_text(data = rob_method_pct, aes(label = paste0("(", round(percentage, 0), "%)"), x = n), 
            hjust = -0.1, size = 12, color = "black", fontface = "bold") +
  scale_fill_identity(guide = "none") +
  scale_x_continuous(expand = c(0, 0), limits = c(0, max(rob_method_count$n)*1.3)) +
  labs(title = NULL, x = NULL, y = NULL) +
  organochlorTHEME() 

bar_risk_of_bias

# ggsave(here("figures", "bar_plot_risk_of_bias.pdf"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "bar_plot_risk_of_bias.jpg"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)

Alluvial plot for risk of bias

Alluvial plot showing the relationship between the Journal Citation Report Category and risk of bias methodology.

# Data Transformation 
robmethod_alluvial <- sd %>% 
  separate_rows(rob_assessment_method, sep = ",\\s+") %>%
  filter(!is.na(rob_assessment_method)) %>%
  separate_rows(Journal_Category_Allocated_Broad, sep = "/\\s+") %>%
  group_by(Journal_Category_Allocated_Broad, rob_assessment_method) %>% 
  count(rob_assessment_method, Journal_Category_Allocated_Broad) %>% 
  summarise(freq = n(), .groups = 'drop') %>% 
  group_by(rob_assessment_method) 

# Create the Alluvial plot
alluvial_risk_of_bias <- robmethod_alluvial %>% 
  ggplot(aes(y = freq ,axis1 = Journal_Category_Allocated_Broad, axis2 = rob_assessment_method)) +
  scale_x_discrete(limits = c("Journal Citation Category", "ROB Assessment Method"), expand = c(.05, .05)) +
  xlab("Variables") +
  geom_alluvium(aes(fill = Journal_Category_Allocated_Broad)) +
  geom_stratum(width = 1/3, fill = "white", color = "black") +
  geom_text(stat = "stratum", aes(label = after_stat(stratum)), size = 5) +
  labs(x= "Variables", y = "Frequency", fill = "Journal Category Allocated") +
  scale_fill_brewer(palette = "Dark2") +
  organochlorTHEME() 

alluvial_risk_of_bias

# ggsave(here("figures", "alluvial_plot_risk_of_bias.pdf"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "alluvial_plot_risk_of_bias.jpg"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)

Bar plot for bias visualizations

Bar plot showing the percentage and total count of bias visualizations used in meta-analyses investigating the impacts of organochlorine pesticides. Note that some meta-analyses may contribute to multiple sections if the study involved the use of multiple bias visualizations.

# Calculate the total count for each category
bias_visualization_count <- sd %>% 
  separate_rows(bias_assessment_visualization, sep = ",\\s+") %>% 
  count(bias_assessment_visualization) %>%
  filter(bias_assessment_visualization != "NA") %>%
  group_by(bias_assessment_visualization) %>%
  summarise(n = sum(n))

# Calculate proportion and percentage for each category
bias_visualization_pct <- bias_visualization_count %>%
  mutate(proportion = n / 83,
         percentage = proportion * 100)

# Create the count plot
bar_bias_visualization <- bias_visualization_count %>%
  ggplot(aes(x = n, y = reorder(bias_assessment_visualization, n), 
             fill = ifelse(grepl("Not reported", bias_assessment_visualization), "#7370b3", "#1b9e77"))) +
  geom_bar(stat = "identity", width = 0.8 , alpha = 0.7) +
  geom_text(aes(label = n, x = n/2, y = reorder(bias_assessment_visualization, n)), 
            hjust = 0.5, size = 12, color = "black") +
  geom_text(data = bias_visualization_pct, aes(label = paste0("(", round(percentage, 1), "%)"), x = n), 
            hjust = -0.1, size = 12, color = "black", fontface = "bold") +
  scale_fill_identity(guide = "none") +
  scale_x_continuous(expand = c(0, 0), limits = c(0, max(bias_visualization_count$n)*1.3)) +
  labs(title = NULL, x = NULL, y = NULL) +
  organochlorTHEME() 

bar_bias_visualization

# ggsave(here("figures", "bar_plot_bias_visualization.pdf"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "bar_plot_bias_visualization.jpg"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)

Alluvial plot for bias visualization method

Alluvial plot showing the relationship between the Journal Citation Report Category and bias visualization method.

# Data Transformation 
bias_vizualisation_alluvial <- sd %>% 
    separate_rows(bias_assessment_visualization, sep = ",\\s+") %>%
    separate_rows(Journal_Category_Allocated_Broad, sep = "/\\s+") %>% 
    filter(!is.na(bias_assessment_visualization)) %>%
    group_by(Journal_Category_Allocated_Broad, bias_assessment_visualization) %>% 
    count(bias_assessment_visualization, Journal_Category_Allocated_Broad) %>% 
    summarise(freq = n(), .groups = 'drop') %>% 
    group_by(bias_assessment_visualization)

# Create the Alluvial plot
alluvial_bias_visualization <- bias_vizualisation_alluvial %>% 
  ggplot(aes(y = freq, axis1 = Journal_Category_Allocated_Broad, axis2 = bias_assessment_visualization)) +
  scale_x_discrete(limits = c("Journal Citation Category", "Bias Vizualization"), expand = c(.05, .05)) +
  xlab("Variables") +
  geom_alluvium(aes(fill = Journal_Category_Allocated_Broad)) +
  geom_stratum(width = 1/4, fill = "white", color = "black") +
  geom_text(stat = "stratum", aes(label = after_stat(stratum)), size = 6) +
  labs(x= "Variables", y = "Frequency", fill = "Journal Category Allocated") +
  scale_fill_brewer(palette = "Dark2") +
  organochlorTHEME() 

alluvial_bias_visualization

# ggsave(here("figures", "alluvial_plot_bias_visualization.pdf"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "alluvial_plot_bias_visualization.jpg"), width = 16, height = 10, units = "cm", scale = 2, dpi = 800)

Circular treemap for existing methodological approaches

A circular treemap showing the counts of each methodological item in existing meta-analysis investigating the impacts of organochlorine pesticides

# Grouping "Medline" and "Pubmed" under "PubMed" and summing the counts
database_count <- database_count %>%
  mutate(database_search = if_else(database_search %in% c("Medline", "Pubmed"), "PubMed", database_search)) %>%
  group_by(database_search) %>%
  summarise(n = sum(n))

# Splitting, grouping, and summing different categories of effect sizes
effectsize_count <- sd %>% 
  separate_rows(effect_size, sep = ",\\s+") %>% 
  count(effect_size) %>%
  filter(effect_size != "NA") %>%
  group_by(effect_size) %>%
  summarise(n = sum(n))

effectsize_count <- effectsize_count %>% 
  mutate(effect_size = if_else(effect_size %in% c("Beta regression", "Correlation coefficient"), "Correlation", effect_size)) %>% 
  mutate(effect_size = if_else(effect_size %in% c("Odds ratio", "Response ratio", "Standardized mean difference", "Log partitioning ratio", "Log odds ratio", "Ratio of means", "Log response ratio"), "Mean difference", effect_size)) %>% 
  mutate(effect_size = if_else(effect_size %in% c("Risk ratio"), "2x2", effect_size)) %>% 
  mutate(effect_size = if_else(effect_size %in% c("Raw weight", "Geometric mean", "Maternal transfer ratio", "Standardized mortality rate", "Transfer rate","Transfer ratio", "Z-score", "Log coefficient variation ratio"), "Other ES", effect_size)) %>% 
  group_by(effect_size) %>%
  summarise(n = sum(n))

# Categorizing software as either "Code-based software" or "GUI" and summing the counts
software_count <- software_count %>%
  mutate(software_analysis = if_else(software_analysis %in% c("Stata", "R", "SAS"), "Code-based", software_analysis)) %>%
  mutate(software_analysis = if_else(software_analysis %in% c("CMAS", "Excel", "RevMan", "XLSTAT"), "GUI", software_analysis)) %>% 
  mutate(software_analysis = if_else(software_analysis %in% c("Not reported"), "No software reported", software_analysis)) %>%
  group_by(software_analysis) %>%
  summarise(n = sum(n))

# Grouping heterogeneity assessment methods and summing the counts
heterogeneity_count <- heterogeneity_count %>% 
  mutate(heterogeneity_assessment_method = if_else(heterogeneity_assessment_method %in% c("Tau square"), "I squared", heterogeneity_assessment_method)) %>% 
  mutate(heterogeneity_assessment_method = if_else(heterogeneity_assessment_method %in% c("Chi square"), "Q statistic", heterogeneity_assessment_method)) %>% 
  mutate(heterogeneity_assessment_method = if_else(heterogeneity_assessment_method %in% c("Not reported"), "No heterogeneity reported", heterogeneity_assessment_method)) %>% 
  group_by(heterogeneity_assessment_method) %>%
  summarise(n = sum(n))

# Grouping bias assessment methods with count <= 3 under "Other BA" and summing the counts
bias_method_count <- bias_method_count %>% 
  mutate(bias_assessment_method = if_else(bias_assessment_method %in% c("Egger's regression test", "Fail safe", "Begg's test", "Kendall's tau statistic"),"Bias statistical test", bias_assessment_method)) %>% 
    mutate(bias_assessment_method = if_else(bias_assessment_method %in% c("Not reported"),"No bias assessment reported", bias_assessment_method)) %>% 
  group_by(bias_assessment_method) %>%
  summarise(n = sum(n))

# Grouping sensitivity analysis methods and summing the counts
sensitivity_count <-  sensitivity_count %>%  
  mutate(sensitivity_analysis_method = if_else(n<= 8, "Other sensitivity analysis", as.character(sensitivity_analysis_method))) %>% 
   mutate(sensitivity_analysis_method = if_else(sensitivity_analysis_method %in% c("Not reported"), "No sensitivity analysis reported",sensitivity_analysis_method)) %>% 
  group_by(sensitivity_analysis_method) %>%
  summarise(n = sum(n))

# Grouping risk of bias assessment methods with count <= 3 under "Other ROB" and summing the counts
rob_method_count <-  rob_method_count %>%  
  mutate(rob_assessment_method = if_else(n<= 3, "Other ROB tool", as.character(rob_assessment_method))) %>% 
    mutate(rob_assessment_method = if_else(rob_assessment_method %in% c("Not reported"), "No risk of bias reported", rob_assessment_method)) %>% 
  group_by(rob_assessment_method) %>%
  summarise(n = sum(n))

# Grouping visualization methods with count <= 3 under "Other Viz" and summing the counts
visualization_count <- visualization_count %>% 
   mutate(visualization_method = if_else(n<= 3, "Other Viz", as.character(visualization_method))) %>% 
  mutate(visualization_method = if_else(visualization_method %in% c("Not reported"), "No vizualization reported", visualization_method)) %>% 
  group_by(visualization_method) %>%
  summarise(n = sum(n))

# Grouping reporting standards types with count <= 2 under "Other guideline" and summing the counts
reporting_guide_count <- reporting_guide_count %>% 
  mutate(reporting_standards_type = ifelse(n<= 2, "Other guideline", as.character(reporting_standards_type))) %>% 
  mutate(reporting_standards_type = ifelse(reporting_standards_type %in% c("Not reported"), "No reporting guideline reported",reporting_standards_type)) %>% 
  group_by(reporting_standards_type) %>%
  summarise(n = sum(n))

# Grouping bias assessment visualization types and summing the counts
bias_visualization_count <- bias_visualization_count %>% 
  mutate(bias_assessment_visualization = if_else(bias_assessment_visualization %in% c("Doi plot", "Trim and fill", "Funnel plot", "Galbraith plot"), "Bias visualization", bias_assessment_visualization)) %>% 
  mutate(bias_assessment_visualization = if_else(bias_assessment_visualization %in% c("Not reported"), "No bias visualization reported", bias_assessment_visualization)) %>% 
  group_by(bias_assessment_visualization) %>%
  summarise(n = sum(n))

# Combine the data frames and unite the methodology types
df <- bind_rows(
  database_count %>% mutate(methodology_type = 'Database Search'),
  effectsize_count %>% mutate(methodology_type = 'Effect Size'),
  software_count %>%  mutate(methodology_type = "Software"),
  heterogeneity_count %>% mutate(methodology_type = "Heterogeneity"),
  sensitivity_count %>% mutate(methodology_type = "Sensitivity_Analysis"),
  bias_method_count %>%  mutate(methodology_type = "Bias Assessment"),
  rob_method_count %>% mutate(methodology_type = "Risk  of Bias"), 
 # visualization_count %>% mutate(methodology_type = "Visualization"),
  reporting_guide_count %>%  mutate(methodology_type = "Reporting Guide"),
  bias_visualization_count %>%  mutate(methodology_type = "Bias Assessment")
) %>% 
 unite(methodology_type_specific, 
       database_search, 
       effect_size,  
       software_analysis,
       heterogeneity_assessment_method, 
       sensitivity_analysis_method, 
       bias_assessment_method,
       rob_assessment_method, 
      # visualization_method, 
       reporting_standards_type, 
       bias_assessment_visualization,
       remove = TRUE, na.rm = TRUE)

# Preparing the edges dataframe for creating the graph
edges <- df %>%
  rename(from = methodology_type, to = methodology_type_specific, size = n) %>%
  select(c(from,to,size)) %>%
  as.data.frame()

# Preparing the vertices dataframe for creating the graph
vertices <- df  %>%
  rename(name = methodology_type_specific, size = n) %>%
  select(c(name,size)) %>%
  as.data.frame()

# Appending unique 'from' values to vertices and their corresponding summed sizes
vertices[(nrow(edges)+1):(nrow(edges)+length(unique(edges$from))),1] <- unique(edges$from)
N <- aggregate(edges$size, list(edges$from), FUN=sum)
vertices[(nrow(edges)+1):(nrow(edges)+length(unique(edges$from))),2] <- N$x

# Creating a graph object from the edges and vertices dataframes
mygraph <- graph_from_data_frame(edges, vertices = vertices)

# Plotting the graph using a 'circlepack' layout
circular_treemap_methods <- ggraph(mygraph, layout = 'circlepack', weight = size) + 
    geom_node_circle(aes(fill = as.factor(depth)), color = NA) +
    scale_fill_manual(values = c("#1b9e77", "#88D1AD")) + 
    geom_node_text(aes(label = name, filter = leaf, size = 10), vjust = -0.3, fontface = "bold") +
    geom_node_text(aes(label = paste0("(", size, ")"), filter = leaf, size = 10), vjust = 1, fontface = "bold") +
    theme_void() +
    theme(legend.position = "none") 

circular_treemap_methods

# ggsave(here("figures", "circular_treemap_methods.pdf"), width = 18, height = 15, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "circular_treemap_methods.jpg"), width = 18, height = 15, units = "cm", scale = 2, dpi = 800)

Donut plot for confound analysis

Donut plot showing the proportion of studies which included confounds (through risk of bias assessments) in the analysis (green = not reported, orange = reported).

# Remove NA values and count Yes/No
confound_data <- sd %>%
  filter(!is.na(confound_analysis)) %>%
  count(confound_analysis) %>%
  mutate(percentage = n / sum(n) * 100)

# Donut Plot with a hole
donut_plot <- ggplot(confound_data, aes(x = 2, y = percentage, fill = confound_analysis)) +
  geom_bar(stat = "identity", width = 1, color = "white") +
  coord_polar(theta = "y", start = 0) +
  geom_text(
    aes(label = paste0(round(percentage, 1), "%")), 
    position = position_stack(vjust = 0.5), 
    size = 5, 
    fontface = "bold",
    color = "white"
  ) +
  scale_fill_manual(values = c("yes" = "#d95f02", "no" = "#1b9e77")) +  # Custom colors
  labs(fill = NULL) +  # Remove legend title
  theme_void() +
  theme(
    legend.position = "none",  # Remove legend
    plot.title = element_text(size = 16, face = "bold", hjust = 0.5)
  ) +
  xlim(0.5, 2.5)  # Creates the hole in the middle

# Save figures
# ggsave(here("figures", "donut_confound.pdf"), plot = donut_plot, width = 8, height = 8, units = "cm", dpi = 800)
# ggsave(here("figures", "donut_confound.jpg"), plot = donut_plot, width = 8, height = 8, units = "cm", dpi = 800)

Section 2

To explore the various characteristics of the organochlorine pesticides literature such as the pesticides used, the impacts elicited in response and the subjects that were investigated.

Bar plot for organochlorine pesticides investigated

A bar plot showing the percentage and total count of total of pesticides investigate in meta-analysis investigating the impacts of organochlorine pesticides. Note: some meta-analysis may contribute to multiple sections if the study involves multiple organochlorine pesticides. Filtered for pesticide counts greater than 6.

# Function to replace long OCP names with abbreviations
replace_ocp <- function(df) {
  df %>% 
    mutate(ocp = case_when(
      # HCH related replacements
      grepl("Hexachlorocyclohexane \\(HCH\\)", ocp, ignore.case = TRUE) ~ "HCH",
      grepl("alpha-Hexachlorocyclohexane \\(alpha-HCH\\)", ocp, ignore.case = TRUE) ~ "α - HCH",
      grepl("beta-Hexachlorocyclohexane \\(beta-HCH\\)", ocp, ignore.case = TRUE) ~ "β - HCH",
      grepl("gamma-Hexachlorocyclohexane \\(gamma-HCH\\)", ocp, ignore.case = TRUE) ~ "Lindane",
      # DDT related replacements
      grepl("Dichlorodiphenyltrichloroethane \\(DDT\\)", ocp, ignore.case = TRUE) ~ "DDT",
      grepl("p,p-Dichlorodiphenyltrichloroethane \\(p,p-DDT\\)", ocp, ignore.case = TRUE) ~ "p,p-DDT",
      grepl("o,p-Dichlorodiphenyltrichloroethane \\(o,p-DDT\\)", ocp, ignore.case = TRUE) ~ "o,p-DDT",
      # DDD related replacements
      grepl("Dichlorodiphenyldichloroethane \\(DDD\\)", ocp, ignore.case = TRUE) ~ "DDD",
      grepl("p,p-Dichlorodiphenyldichloroethane \\(p,p-DDD\\)", ocp, ignore.case = TRUE) ~ "p,p-DDD",
      grepl("o,p-Dichlorodiphenyldichloroethane \\(o,p-DDD\\)", ocp, ignore.case = TRUE) ~ "o,p-DDD",
      # DDE related replacements
      grepl("Dichlorodiphenyldichloroethylene \\(DDE\\)", ocp, ignore.case = TRUE) ~ "DDE",
      grepl("p,p-Dichlorodiphenyldichloroethylene \\(p,p-DDE\\)", ocp, ignore.case = TRUE) ~ "p,p-DDE",
      grepl("o,p-Dichlorodiphenyldichloroethylene \\(o,p-DDE\\)", ocp, ignore.case = TRUE) ~ "o,p-DDE",
      TRUE ~ ocp  # no change for any others
    ))
}

# Transform the data 
ocp_count <- ocp %>% 
  separate_rows(ocp, sep = ",\\s+") %>% 
  replace_ocp() %>% 
  count(ocp) %>% 
  filter(!is.na(ocp)) %>%  # filter out NA 
  arrange(desc(n)) %>% 
  mutate(ocp = ifelse(n <= 6, "other OCP", as.character(ocp))) %>% 
  group_by(ocp) %>% 
  summarise(n = sum(n))

# Calculate the proportion and percentage of each OCP
ocp_pct <- ocp_count %>%
  mutate(proportion = n / 104,
         percentage = proportion * 100)

# Create the count plot for OCPs
bar_plot_ocp <- ocp_count %>%
  ggplot(aes(x = n, y = reorder(ocp, n), fill = "#1b9e77")) +
  geom_bar(stat = "identity", width = 0.8, alpha = 0.7) +
  geom_text(aes(label = n, x = n / 2, y = reorder(ocp, n)),
            hjust = 0.5, size = 7, color = "black") +
  geom_text(data = ocp_pct,
            aes(label = paste0("(", round(percentage, 1), "%)"), x = n),
            hjust = -0.1, size = 7, color = "black", fontface = "bold") +
  scale_fill_identity(guide = "none") +
  scale_x_continuous(name = "Article Count", expand = c(0, 0), limits = c(0, max(ocp_count$n)*1.2)) +
  labs(title = NULL, x = NULL, y = NULL) +
  organochlorTHEME() +
  theme(axis.text.y = element_text(size = 20))  

bar_plot_ocp

# ggsave(here("figures", "bar_plot_pesticide_investigation.pdf"), 
#        plot = bar_plot_ocp, width = 25, height = 15, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "bar_plot_pesticide_investigation.jpg"), 
#        plot = bar_plot_ocp, width = 25, height = 15, units = "cm", scale = 2, dpi = 800)

Bar plot for subjects investigated

A bar plot showing the percentage and total count of total of subjects investigate in meta-analysis investigating the impacts of organochlorine pesticides. Note: some meta-analysis may contribute to multiple sections if the study involves multiple subjects

# Calculate total count for each category
subject_count <- sub %>% 
  separate_rows(subject, sep = ",\\s+") %>% 
  mutate(subject = ifelse(grepl("Non-human animal", subject, ignore.case = TRUE),
                          "Non-human\nanimal", subject)) %>% 
  count(subject)

# Calculate proportion and percentage for each category
subject_pct <- subject_count %>%
  mutate(proportion = n / 105,
         percentage = proportion * 100)

# Create the count plot for subjects
bar_plot_subject <- subject_count %>%
  ggplot(aes(x = n, y = reorder(subject, n), fill = "#1b9e77")) +
  geom_bar(stat = "identity", width = 0.8 , alpha = 0.7) +
  geom_text(aes(label = n, x = n / 2, y = reorder(subject, n)), 
            hjust = 0.5, size = 12, color = "black") +
  geom_text(data = subject_pct, 
            aes(label = paste0("(", round(percentage, 1), "%)"), x = n),
            hjust = -0.1, size = 12, color = "black", fontface = "bold") +
  scale_fill_identity(guide = "none") +
  scale_x_continuous(name = "Article Count", expand = c(0, 0), limits = c(0, max(subject_count$n)*1.2)) +
  labs(title = NULL, x = NULL, y = NULL) +
  organochlorTHEME()

bar_plot_subject

# ggsave(here("figures", "bar_plot_subject_investigation.pdf"), 
#        plot = bar_plot_subject, width = 25, height = 15, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "bar_plot_subject_investigation.jpg"), 
#        plot = bar_plot_subject, width = 25, height = 15, units = "cm", scale = 2, dpi = 800)

Bar plot for impacts investigated (filtered)

A bar plot showing the percentage and total count of total of subjects investigate in meta-analysis investigating the impacts of organochlorine pesticides. Note: some meta-analysis may contribute to multiple sections if the study involves multiple subjects. Filtered for impact counts greater than 1.

# Calculate total count for each category
impact_count <- im %>% 
  separate_rows(impact, sep = ",\\s+") %>% 
  count(impact) %>% 
  filter(impact != "NA") %>% 
  mutate(impact = ifelse(n <= 2, "other", as.character(impact))) %>% 
  group_by(impact) %>%
  summarise(n = sum(n))

# Calculate proportion and percentage for each category
impact_pct <- impact_count %>%
  mutate(proportion = n / sum(impact_count$n),
         percentage = proportion * 100)

# Create the count plot for impacts 
bar_plot_impact_filtered <- impact_count %>%
  ggplot(aes(x = n, y = reorder(impact, n), fill = "#1b9e77")) +
  geom_bar(stat = "identity", width = 0.8 , alpha = 0.7) +
  geom_text(aes(label = n, x = n / 2, y = reorder(impact, n)),
            hjust = 0.5, size = 10, color = "black") +
  geom_text(data = impact_pct,
            aes(label = paste0("(", round(percentage, 1), "%)"), x = n),
            hjust = -0.1, size = 10, color = "black", fontface = "bold") +
  scale_fill_identity(guide = "none") +
  scale_x_continuous(name = "Article Count", expand = c(0, 0), limits = c(0, max(impact_count$n)*1.3)) +
  labs(title = NULL, x = NULL, y = NULL) +
  organochlorTHEME()

bar_plot_impact_filtered

# ggsave(here("figures", "bar_plot_impact_investigated_filtered.pdf"),
#        plot = bar_plot_impact_filtered, width = 25, height = 15, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "bar_plot_impact_investigated_filtered.jpg"),
#        plot = bar_plot_impact_filtered, width = 25, height = 15, units = "cm", scale = 2, dpi = 800)

Bar plot for broad impact categories

A bar plot showing the percentage and total count of total of impact categories investigated in meta-analysis investigating the impacts of organochlorine pesticides. Note: some meta-analysis may contribute to multiple sections if the study involves multiple impacts

# Create a column for broad impacts
im <- im %>%
  separate_rows(impact, sep = ",\\s+") %>% 
  mutate(impact_broad = case_when(
    impact %in% c("parkinsons disease", "alzheimers disease", "autism spectrum disorder", 
                  "brain tumour", "amyotrophic lateral sclerosis") ~ "Neurological",
    impact %in% c("concentration", "contamination") ~ "Concentration",
    impact %in% c("diabetes", "thyroid function", "hypertension", "endometriosis") ~ "Endocrine",
    grepl("cancer", impact, ignore.case = TRUE) |
      impact %in% c("leukemia", "lymphoma", "multiple myeloma", "neuroblastoma") ~ "Carcinogen",
    impact %in% c("respiratory health", "cardiovascular disease", "asthma", "prolonged bradycardia") ~ "Cardiovascular",
    impact %in% c("obesity", "adiposity") ~ "Obesity",
    impact %in% c("sperm quality", "neuroblastoma", "hypospadias", "cryptochidism", 
                  "reproductive system") ~ "Reproduction",
    TRUE ~ "Other Impact"
  ))

# Calculate total count for each category
impact_count_broad <- im %>% 
  separate_rows(impact_broad, sep = ",\\s+") %>% 
  count(impact_broad) %>% 
  filter(impact_broad != "NA") %>% 
  group_by(impact_broad) %>% 
  summarise(n = sum(n))

# Calculate proportion and percentage for each category
impact_pct_broad <- impact_count_broad %>%
  mutate(proportion = n / 105,
         percentage = proportion * 100)

# Create the count plot for impacts 
bar_plot_impact_broad <- impact_count_broad %>%
  ggplot(aes(x = n, y = reorder(impact_broad, n), fill = "#1b9e77")) +
  geom_bar(stat = "identity", width = 0.8 , alpha = 0.7) +
  geom_text(aes(label = n, x = n / 2, y = reorder(impact_broad, n)),
            hjust = 0.5, size = 10, color = "black") +
  geom_text(data = impact_pct_broad,
            aes(label = paste0("(", round(percentage, 1), "%)"), x = n),
            hjust = -0.1, size = 10, color = "black", fontface = "bold") +
  scale_fill_identity(guide = "none") +
  scale_x_continuous(name = "Article Count", expand = c(0, 0), limits = c(0, max(impact_count_broad$n)*1.3)) +
  labs(title = NULL, x = NULL, y = NULL) +
  organochlorTHEME()

bar_plot_impact_broad

# ggsave(here("figures", "bar_plot_broad_impact_category.pdf"),
#        plot = bar_plot_impact_broad, width = 25, height = 15, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "bar_plot_broad_impact_category.jpg"),
#        plot = bar_plot_impact_broad, width = 25, height = 15, units = "cm", scale = 2, dpi = 800)

Alluvial plot: pesticide exposure, subject, and impact

An alluvial plot showing the relationships between the pesticide of exposure, the subject being exposed and the impact of exposure

# Function to change OCP to be more general
replace_ocp2 <- function(df) {
  df %>% 
    mutate(ocp = case_when(
      grepl("Chlordane", ocp, ignore.case = TRUE) ~ "Chlordane",  
      grepl("Endosulfan", ocp, ignore.case = TRUE) ~ "Endosulfan", 
      grepl("Nonachlor", ocp, ignore.case = TRUE) ~ "Nonachlore", 
      grepl("Heptachlor", ocp, ignore.case = TRUE) ~ "Heptachlor",
      grepl("TCDD", ocp, ignore.case = TRUE) ~ "TCDD", 
      grepl("Endrin", ocp, ignore.case = TRUE) ~ "Endrin",
      grepl("Hexachlorobenzene", ocp, ignore.case = TRUE) ~ "HCH",
      grepl("Lindane", ocp, ignore.case = TRUE) ~ "HCH", 
      grepl("Hexachlorocyclohexane \\(HCH\\)", ocp, ignore.case = TRUE) ~ "HCH",
      grepl("alpha-Hexachlorocyclohexane \\(alpha-HCH\\)", ocp, ignore.case = TRUE) ~ "HCH",
      grepl("beta-Hexachlorocyclohexane \\(beta-HCH\\)", ocp, ignore.case = TRUE) ~ "HCH",
      grepl("gamma-Hexachlorocyclohexane \\(gamma-HCH\\)", ocp, ignore.case = TRUE) ~ "HCH",
      grepl("Dichlorodiphenyltrichloroethane \\(DDT\\)", ocp, ignore.case = TRUE) ~ "DDT",
      grepl("p,p-Dichlorodiphenyltrichloroethane \\(p,p-DDT\\)", ocp, ignore.case = TRUE) ~ "DDT",
      grepl("o,p-Dichlorodiphenyltrichloroethane \\(o,p-DDT\\)", ocp, ignore.case = TRUE) ~ "DDT",
      grepl("Dichlorodiphenyldichloroethane \\(DDD\\)", ocp, ignore.case = TRUE) ~ "DDD",
      grepl("p,p-Dichlorodiphenyldichloroethane \\(p,p-DDD\\)", ocp, ignore.case = TRUE) ~ "DDD",
      grepl("o,p-Dichlorodiphenyldichloroethane \\(o,p-DDD\\)", ocp, ignore.case = TRUE) ~ "DDD",
      grepl("Dichlorodiphenyldichloroethylene \\(DDE\\)", ocp, ignore.case = TRUE) ~ "DDE",
      grepl("p,p-Dichlorodiphenyldichloroethylene \\(p,p-DDE\\)", ocp, ignore.case = TRUE) ~ "DDE",
      grepl("o,p-Dichlorodiphenyldichloroethylene \\(o,p-DDE\\)", ocp, ignore.case = TRUE) ~ "DDE",
      TRUE ~ ocp
    ))
}

# Transform the data 
alluvial_data <- im %>%
  left_join(ocp, by = "study_id") %>%
  left_join(sub, by = "study_id") %>%
  separate_rows(subject, sep = ",\\s+") %>% 
  separate_rows(ocp, sep = ",\\s+") %>% 
  separate_rows(impact_broad, sep = ",\\s+") %>%
  replace_ocp2() %>%
  filter(!grepl("not reported", ocp, ignore.case = TRUE)) %>%
  group_by(ocp, subject, impact_broad) %>%
  summarise(freq = n(), .groups = 'drop') %>%
  group_by(ocp) %>%
  filter(sum(freq) > 10) %>%  
  group_by(impact_broad) %>% 
  filter(sum(freq) > 5) %>% 
  mutate(subject = factor(subject, levels = c("Environment", "Non-human animal", "Human"), ordered = TRUE))

# Make alluvial plot
alluvial_plot_exposure <- alluvial_data %>% 
  ggplot(aes(axis1 = ocp, axis2 = subject, axis3 = impact_broad, y = freq)) +
  scale_x_discrete(limits = c("Organochlorine Pesticide", "Subject", "Impact"), expand = c(.05, .10)) +
  xlab("Variables") +
  ylab("Frequency") +  
  geom_alluvium(aes(fill = subject)) +
  geom_stratum(width = 1/2, fill = "white", color = "black") +
  geom_text(stat = "stratum", aes(label = after_stat(stratum)), size = 5, fontface = "bold") +  
  theme_minimal() +
  theme(axis.text = element_text(size = 15),  
        axis.title = element_text(size = 20),
        legend.position = "none",
        panel.grid.major = element_blank(),  
        panel.grid.minor = element_blank()) + 
  scale_fill_brewer(palette = "Dark2", name = "Subject Category")

alluvial_plot_exposure

# ggsave(here("figures", "alluvial_plot_exposure_subject_impact.pdf"), 
#        plot = alluvial_plot_exposure, width = 25, height = 15, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "alluvial_plot_exposure_subject_impact.jpg"), 
#        plot = alluvial_plot_exposure, width = 25, height = 15, units = "cm", scale = 2, dpi = 800)


# ggsave(here("figures", "figs29.pdf"), width =18, height = 12, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "figs29.jpg"), width = 18, height = 12, units = "cm", scale = 2, dpi = 800)

Figure 3

A bubble plot showing the counts of each pesticide per impact included in current meta-analysis on the impacts of organochlorine pesticides

# Join the organochlorine pesticide details with the impact details
ocp_im <- left_join(ocp, im ,sub, by = "study_id") 

# Separate rows in "ocp_im"
ocp_im1 <- separate_rows(ocp_im, ocp , sep = ", ", convert = TRUE)


# Group by "ocp" and "impact" and summarize count
ocp_im_summary <- ocp_im1 %>%
  mutate(ocp = str_trim(ocp),
         impact_broad = str_trim(impact_broad)) %>%
    replace_ocp2() %>% 
  group_by(ocp, impact_broad) %>%
  summarise(count = n(), .groups = "drop") %>% 
  mutate(ocp = ifelse(grepl("no chemical classification", ocp, ignore.case = TRUE), "no chemical\n classification", ocp))

# Filter for top 8 pesticides 
top_pesticides <- ocp_im_summary %>%
  filter(ocp != "not reported") %>%
  group_by(ocp) %>%
  summarise(total_count = sum(count)) %>%
  top_n(8, total_count) %>%
  pull(ocp) 


ocp_im_summary_filtered <- ocp_im_summary %>%
  filter(ocp %in% top_pesticides)

fig3 <- ocp_im_summary_filtered %>% 
  ggplot(aes(x = fct_rev(fct_reorder(impact_broad, count, .fun = 'sum')),
             y = fct_reorder(ocp, count, .fun = 'sum'),
             size = count,
             fill = impact_broad)) +
  geom_point(shape = 21, color = "white") +
  geom_text(aes(label = count), size = 20, fontface = "bold") +
  labs(title = NULL, x = NULL, y =NULL) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(size = 35),  
    axis.text.y = element_text(size = 40, hjust = 1),  
    legend.position = "none") +
  scale_size_continuous(range = c(30, 80))

fig3

# ggsave(here("figures", "fig3.pdf"), width = 40, height = 25, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "fig3.jpg"), width = 40, height = 25, units = "cm", scale = 2, dpi = 800)

Section 3

To investigate global research output and collaboration networks

Exploratory bibliometric analysis

# Perform bibliometric analysis
bibliometric_analysis <- biblioAnalysis(bib_sco)

# Adjust plot parameters
par(cex=1.5)

# Explore results
plot(bibliometric_analysis)

summary(bibliometric_analysis)
## 
## 
## MAIN INFORMATION ABOUT DATA
## 
##  Timespan                              1993 : 2022 
##  Sources (Journals, Books, etc)        45 
##  Documents                             100 
##  Annual Growth Rate %                  9.25 
##  Document Average Age                  9.78 
##  Average citations per doc             58.6 
##  Average citations per year per doc    5.07 
##  References                            7548 
##  
## DOCUMENT TYPES                     
##  article               50 
##  conference paper      2 
##  review                48 
##  
## DOCUMENT CONTENTS
##  Keywords Plus (ID)                    1592 
##  Author's Keywords (DE)                258 
##  
## AUTHORS
##  Authors                               544 
##  Author Appearances                    684 
##  Authors of single-authored docs       1 
##  
## AUTHORS COLLABORATION
##  Single-authored docs                  1 
##  Documents per Author                  0.184 
##  Co-Authors per Doc                    6.84 
##  International co-authorships %        41 
##  
## 
## Annual Scientific Production
## 
##  Year    Articles
##     1993        1
##     1995        1
##     1999        1
##     2000        1
##     2004        2
##     2006        3
##     2007        1
##     2008        2
##     2009        1
##     2010        4
##     2011        3
##     2012        5
##     2013        5
##     2014        9
##     2015        7
##     2016       11
##     2017        4
##     2018        2
##     2019        7
##     2020        8
##     2021        9
##     2022       13
## 
## Annual Percentage Growth Rate 9.25 
## 
## 
## Most Productive Authors
## 
##       Authors        Articles    Authors        Articles Fractionalized
## 1  LISON D                  7 LISON D                             2.000
## 2  VAN MAELE-FABRY G        7 VAN MAELE-FABRY G                   2.000
## 3  BONDE JP                 5 DAVIS WJ                            1.000
## 4  BALLESTER F              4 GAMET-PAYRASTRE L                   0.867
## 5  CHEVRIER C               4 KREWSKI D                           0.867
## 6  EGGESBØ M                4 HOET P                              0.833
## 7  GOVARTS E                4 FU X                                0.750
## 8  SCHOETERS G              4 MUÑOZ CC                            0.750
## 9  TRNOVEC T                4 VERMEIREN P                         0.750
## 10 ZHANG Y                  4 LEVY LS                             0.700
## 
## 
## Top manuscripts per citations
## 
##                                       Paper                                      DOI  TC TCperYear  NTC
## 1  BROWN TP, 2006, ENVIRON HEALTH PERSPECT           10.1289/ehp.8095                329     16.45 1.85
## 2  GOVARTS E, 2012, ENVIRON HEALTH PERSPECT          10.1289/ehp.1103767             228     16.29 1.81
## 3  PEZZOLI G, 2013, NEUROLOGY                        10.1212/WNL.0b013e318294b3c8    207     15.92 2.08
## 4  BONDE JP, 2016, HUM REPROD UPDATE                 10.1093/HUMUPD/DMW036           188     18.80 2.24
## 5  RIGÉT F, 2010, SCI TOTAL ENVIRON                  10.1016/j.scitotenv.2009.07.036 162     10.12 1.50
## 6  VAN DER MARK M, 2012, ENVIRON HEALTH PERSPECT     10.1289/ehp.1103881             161     11.50 1.28
## 7  OJAJÄRVI IA, 2000, OCCUP ENVIRON MED              10.1136/oem.57.5.316            153      5.88 1.00
## 8  SCHINASI L, 2014, INT J ENVIRON RES PUBLIC HEALTH 10.3390/ijerph110404449         148     12.33 2.90
## 9  SONG Y, 2016, J DIABETES                          10.1111/1753-0407.12325         140     14.00 1.67
## 10 ADAMI HO, 1995, CANCER CAUSES CONTROL             10.1007/BF00054165              140      4.52 1.00
## 
## 
## Corresponding Author's Countries
## 
##           Country Articles   Freq SCP MCP MCP_Ratio
## 1  CHINA                17 0.1753  12   5     0.294
## 2  USA                  11 0.1134   9   2     0.182
## 3  BELGIUM               7 0.0722   5   2     0.286
## 4  CANADA                6 0.0619   3   3     0.500
## 5  FRANCE                6 0.0619   2   4     0.667
## 6  BRAZIL                5 0.0515   5   0     0.000
## 7  DENMARK               5 0.0515   0   5     1.000
## 8  SPAIN                 5 0.0515   0   5     1.000
## 9  NETHERLANDS           4 0.0412   3   1     0.250
## 10 UNITED KINGDOM        4 0.0412   3   1     0.250
## 
## 
## SCP: Single Country Publications
## 
## MCP: Multiple Country Publications
## 
## 
## Total Citations per Country
## 
##      Country      Total Citations Average Article Citations
## 1  DENMARK                    687                     137.4
## 2  USA                        686                      62.4
## 3  CHINA                      607                      35.7
## 4  UNITED KINGDOM             567                     141.8
## 5  BELGIUM                    488                      69.7
## 6  CANADA                     417                      69.5
## 7  FRANCE                     389                      64.8
## 8  NETHERLANDS                259                      64.8
## 9  ITALY                      207                     207.0
## 10 SPAIN                      181                      36.2
## 
## 
## Most Relevant Sources
## 
##                                  Sources        Articles
## 1  ENVIRONMENTAL HEALTH PERSPECTIVES                  10
## 2  SCIENCE OF THE TOTAL ENVIRONMENT                    9
## 3  ENVIRONMENT INTERNATIONAL                           7
## 4  CANCER CAUSES AND CONTROL                           5
## 5  ENVIRONMENTAL RESEARCH                              5
## 6  ENVIRONMENTAL SCIENCE AND POLLUTION RESEARCH        5
## 7  ENVIRONMENTAL SCIENCE AND TECHNOLOGY                4
## 8  SCIENTIFIC REPORTS                                  4
## 9  CHEMOSPHERE                                         3
## 10 ENVIRONMENTAL POLLUTION                             3
## 
## 
## Most Relevant Keywords
## 
##    Author Keywords (DE)      Articles Keywords-Plus (ID)     Articles
## 1      META-ANALYSIS               43 ENVIRONMENTAL EXPOSURE       92
## 2      PESTICIDES                  28 HUMAN                        84
## 3      SYSTEMATIC REVIEW           18 PESTICIDE                    79
## 4      OCCUPATIONAL EXPOSURE        8 HUMANS                       71
## 5      DDT                          7 FEMALE                       70
## 6      CHILD                        6 META ANALYSIS                64
## 7      DDE                          5 PESTICIDES                   60
## 8      BREAST CANCER                4 OCCUPATIONAL EXPOSURE        57
## 9      INSECTICIDES                 4 MALE                         56
## 10     ORGANOCHLORINES              4 PRIORITY JOURNAL             53
str(bibliometric_analysis)
## List of 26
##  $ Articles            : int 100
##  $ Authors             : 'table' int [1:544(1d)] 7 7 5 4 4 4 4 4 4 4 ...
##   ..- attr(*, "dimnames")=List of 1
##   .. ..$ AU: chr [1:544] "LISON D" "VAN MAELE-FABRY G" "BONDE JP" "BALLESTER F" ...
##  $ AuthorsFrac         :'data.frame':    544 obs. of  2 variables:
##   ..$ Author   : chr [1:544] "LISON D" "VAN MAELE-FABRY G" "DAVIS WJ" "GAMET-PAYRASTRE L" ...
##   ..$ Frequency: num [1:544] 2 2 1 0.867 0.867 ...
##  $ FirstAuthors        : chr [1:100] "LAMAT H" "YIPEI Y" "MOTA TFM" "HE H" ...
##  $ nAUperPaper         : int [1:100] 8 7 4 6 5 6 2 5 5 2 ...
##  $ Appearances         : int 684
##  $ nAuthors            : int 544
##  $ AuMultiAuthoredArt  : int 543
##  $ AuSingleAuthoredArt : int 1
##  $ MostCitedPapers     :'data.frame':    100 obs. of  5 variables:
##   ..$ Paper         : chr [1:100] "BROWN TP, 2006, ENVIRON HEALTH PERSPECT" "GOVARTS E, 2012, ENVIRON HEALTH PERSPECT" "PEZZOLI G, 2013, NEUROLOGY" "BONDE JP, 2016, HUM REPROD UPDATE" ...
##   ..$ DOI           : chr [1:100] "10.1289/ehp.8095" "10.1289/ehp.1103767" "10.1212/WNL.0b013e318294b3c8" "10.1093/HUMUPD/DMW036" ...
##   ..$ TC            : num [1:100] 329 228 207 188 162 161 153 148 140 140 ...
##   ..$ TCperYear     : num [1:100] 16.4 16.3 15.9 18.8 10.1 ...
##   ..$ NTC           : num [1:100] 1.85 1.81 2.08 2.24 1.5 ...
##  $ Years               : num [1:100] 2022 2022 2022 2022 2022 ...
##  $ FirstAffiliation    : chr [1:100] "UNIVERSITÉ CLERMONT AUVERGNE" "PEKING UNIVERSITY HEALTH SCIENCE CENTER" "UNIVERSIDADE ESTADUAL DO PARANÁ (UNESPAR)" "ANHUI MEDICAL UNIVERSITY" ...
##  $ Affiliations        : 'table' int [1:289(1d)] 7 7 6 6 6 5 5 5 5 5 ...
##   ..- attr(*, "dimnames")=List of 1
##   .. ..$ AFF: chr [1:289] "UNIVERSITÉ CATHOLIQUE DE LOUVAIN" "UNIVERSITY OF COPENHAGEN" "HUAZHONG UNIVERSITY OF SCIENCE AND TECHNOLOGY" "IMPERIAL COLLEGE LONDON" ...
##  $ Aff_frac            :'data.frame':    289 obs. of  2 variables:
##   ..$ Affiliation: chr [1:289] "UNIVERSITÉ CATHOLIQUE DE LOUVAIN" "HUAZHONG UNIVERSITY OF SCIENCE AND TECHNOLOGY" "UNIVERSIDADE FEDERAL DO PARANÁ" "UNIVERSITY OF OTTAWA" ...
##   ..$ Frequency  : num [1:289] 4.67 2.67 2 1.89 1.5 ...
##  $ CO                  : chr [1:100] "FRANCE" "CHINA" "BRAZIL" "CHINA" ...
##  $ Countries           : 'table' int [1:28(1d)] 17 11 7 6 6 5 5 5 4 4 ...
##   ..- attr(*, "dimnames")=List of 1
##   .. ..$ Tab: chr [1:28] "CHINA" "USA" "BELGIUM" "CANADA" ...
##  $ CountryCollaboration:'data.frame':    28 obs. of  3 variables:
##   ..$ Country: chr [1:28] "CHINA" "USA" "BELGIUM" "CANADA" ...
##   ..$ SCP    : num [1:28] 12 9 5 3 2 5 0 0 3 3 ...
##   ..$ MCP    : num [1:28] 5 2 2 3 4 0 5 5 1 1 ...
##  $ TotalCitation       : num [1:100] 4 1 3 4 8 2 22 11 1 1 ...
##  $ TCperYear           : num [1:100] 1 0.25 0.75 1 2 0.5 5.5 2.75 0.25 0.25 ...
##  $ Sources             : 'table' int [1:45(1d)] 10 9 7 5 5 5 4 4 3 3 ...
##   ..- attr(*, "dimnames")=List of 1
##   .. ..$ SO: chr [1:45] "ENVIRONMENTAL HEALTH PERSPECTIVES" "SCIENCE OF THE TOTAL ENVIRONMENT" "ENVIRONMENT INTERNATIONAL" "CANCER CAUSES AND CONTROL" ...
##  $ DE                  : 'table' int [1:258(1d)] 43 28 18 8 7 6 5 4 4 4 ...
##   ..- attr(*, "dimnames")=List of 1
##   .. ..$ Tab: chr [1:258] "META-ANALYSIS" "PESTICIDES" "SYSTEMATIC REVIEW" "OCCUPATIONAL EXPOSURE" ...
##  $ ID                  : 'table' int [1:1592(1d)] 92 84 79 71 70 64 60 57 56 53 ...
##   ..- attr(*, "dimnames")=List of 1
##   .. ..$ Tab: chr [1:1592] "ENVIRONMENTAL EXPOSURE" "HUMAN" "PESTICIDE" "HUMANS" ...
##  $ Documents           : 'table' int [1:3(1d)] 50 2 48
##   ..- attr(*, "dimnames")=List of 1
##   .. ..$ : chr [1:3] "ARTICLE              " "CONFERENCE PAPER     " "REVIEW               "
##  $ IntColl             : num 41
##  $ nReferences         : int 7548
##  $ DB                  : chr "SCOPUS"
##  - attr(*, "class")= chr "bibliometrix"

Bar plot of most productive countries

Most productive countries for meta-analyses included in the systematic review map Blue is for single country publications (i.e., countries with authors from a single country) and red is for multiple country publications (i.e., countries with authors from multiple countries).

# Extract country collaboration information
country_data <- bibliometric_analysis$CountryCollaboration
country_tibble <- as_tibble(country_data)

# Reshape data into long format
country_tibble_long <- country_tibble %>% 
  pivot_longer(cols = c(SCP, MCP), names_to = "Country_Collaboration", values_to = "value")

# Summarize and filter for top ten countries
top_countries <- country_tibble_long %>%
  group_by(Country) %>%
  summarize(Total = sum(value)) %>%
  arrange(desc(Total)) %>%
  slice_head(n = 10)

# Filter original dataset to keep only the top ten countries
country_tibble_long_filtered <- country_tibble_long %>%
  filter(Country %in% top_countries$Country)

# Create stacked bar plot
bar_plot_countries <- ggplot(country_tibble_long_filtered, aes(fill = Country_Collaboration, y = value, x = Country)) +
  geom_bar(position = "stack", stat = "identity") +
  coord_flip() +
  organochlorTHEME()

bar_plot_countries

# ggsave(here("figures", "bar_plot_countries.pdf"), width = 25, height = 15, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "bar_plot_countries.jpg"), width = 25, height = 15, units = "cm", scale = 2, dpi = 800)

Bar plot of top authors

authors_data <- bibliometric_analysis$Authors
authors_tibble <- as_tibble(authors_data)

# Slice top 10 authors
authors_tibble_filtered <- authors_tibble %>%
  slice_head(n = 10)

bar_plot_authors <- ggplot(authors_tibble_filtered, aes(y = n, x = reorder(AU, n))) +
  geom_bar(stat = "identity", width = 0.8, alpha = 0.7, fill = "#1b9e77") +
  geom_text(aes(label = n, y = n/2), hjust = 0.5, color = "black", size = 10) +
  coord_flip() +
  organochlorTHEME()

bar_plot_authors

# ggsave(here("figures", "bar_plot_top_authors.pdf"), width = 25, height = 15, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "bar_plot_top_authors.jpg"), width = 25, height = 15, units = "cm", scale = 2, dpi = 800)

Figure 4

Heat map of world showing the country-level counts for first authors’ country of affiliation of meta-analysis investigating the impacts of organochlorine pesticides. Grey indicates no publications affiliated with a given country in our data set.

# Extract country information from the "AU1_CO" and "AU_CO" fields of the "bib_sco" dataset
bibmap <- metaTagExtraction(bib_sco, Field = "AU1_CO", sep = ";") 
bibmap <- metaTagExtraction(bibmap, Field = "AU_CO", sep = ";") 

# Create a data frame with counts of articles from each country
firstcountrycounts <- bibmap %>% 
  group_by(AU1_CO) %>% 
  count() %>% 
  filter(!is.na(AU1_CO))  

# Load world map data and remove countries with longitude >180 to make an equal projection-like map
world_map <- map_data("world") %>% 
  filter(! long > 180)

# Format country names to match regions on the world map
firstcountrycounts$region <- str_to_title(firstcountrycounts$AU1_CO)
firstcountrycounts$region[firstcountrycounts$region == "Usa"] <- "USA" 
firstcountrycounts$region[firstcountrycounts$region == "Korea"] <- "South Korea"
firstcountrycounts$region[firstcountrycounts$region == "United Kingdom"] <- "UK"

# Join count data with map data and set missing counts to zero
emptymap <- tibble(region = unique(world_map$region), n = rep(0,length(unique(world_map$region))))
fullmap <- left_join(emptymap, firstcountrycounts, by = "region")
fullmap$n <- fullmap$n.x + fullmap$n.y
fullmap$n[is.na(fullmap$n)] <- 0

fig4 <- fullmap %>%
  ggplot(aes(fill = n, map_id = region)) +
  geom_map(map = world_map, color = "gray50") +
  expand_limits(x = world_map$long, y = world_map$lat) +
  coord_map("mercator", xlim = c(-180, 180), ylim = c(-50, 90)) +  
  theme(
    axis.text = element_blank(),  
    axis.title = element_blank(),  
    legend.position = "bottom",
    legend.box = "horizontal",  
    legend.box.just = "center",  
    legend.margin = margin(t = 10, unit = "pt"),  
    legend.text = element_text(size = 20),  
    legend.title = element_text(size = 20, face = "bold"),  
    legend.key.width = unit(30, "mm"), 
    panel.background = element_rect(fill = "white")
  ) +
  scale_fill_gradient(
    low = "#98FB98", high = "#006400",
    name = "First Author Count",  
    na.value = "gray70",
    limits = c(1, 20)
  ) +
  guides(
    fill = guide_colourbar(
      barwidth = unit(210, units = "mm"),
      barheight = unit(5, units = "mm")
    )
  )

fig4

 # ggsave(here("figures", "fig4.pdf"), width = 21, height = 12, units = "cm", scale = 2, dpi = 800)
 # ggsave(here("figures", "fig4.jpg"), width = 21, height = 12, units = "cm", scale = 2, dpi = 800)

Europe map of first-author affiliations

Heat map of Europe showing the country-level counts for first authors’ country of affiliation of meta-analysis investigating the impacts of organochlorine pesticides. Grey indicates no publications affiliated with a given country in our data set.

heat_map_europe <- fullmap %>%
  ggplot(aes(fill = n, map_id = region)) +
  geom_map(map = world_map, color = "gray50") +
  coord_map("mercator", ylim = c(35, 65), xlim = c(-35, 45)) + 
  theme(
    axis.text = element_blank(),  
    axis.title = element_blank(),  
    legend.box = "horizontal",  
    legend.box.just = "center",  
    legend.margin = margin(t = 10, unit = "pt"),  
    legend.text = element_text(size = 16),  
    legend.title = element_text(size = 18, face = "bold"),  
    legend.key.width = unit(30, "mm"),
    legend.position = "bottom",
    panel.background = element_rect(fill = "white")
  ) +
  scale_fill_gradient(
    low = "#98FB98", high = "#006400",
    name = "First Author Count", na.value = "gray70",
    limits = c(1, 10), breaks = seq(0, 10, length.out = 6)
  )

heat_map_europe

# ggsave(here("figures", "heat_map_europe_authors.pdf"), width = 25, height = 15, units = "cm", scale = 2, dpi = 800)
# ggsave(here("figures", "heat_map_europe_authors.jpg"), width = 25, height = 15, units = "cm", scale = 2, dpi = 800)

Chord diagram of country collaborations

Chord diagram of collaborations across countries. Countries represent the location of the primary authors’ affiliated institution.

jpeg(filename = here("figures", "chord_diagram_country_collaborations.jpg"), width = 800, height = 800)

# Extract countries from the affiliations
bib_sco2 <- metaTagExtraction(bib_sco, Field = "AU_CO", sep = ";")

# Create a network matrix of collaborations between countries
NetMatrix_country <- biblioNetwork(bib_sco2, analysis = "collaboration", network = "countries", sep = ";")
NetMatrix_country <- as.matrix(NetMatrix_country)

# Remove lower triangle duplication
NetMatrix_country[lower.tri(NetMatrix_country)] <- 0 

# Standardize some country names
colnames(NetMatrix_country) <- str_to_title(colnames(NetMatrix_country))
rownames(NetMatrix_country) <- str_to_title(rownames(NetMatrix_country))
colnames(NetMatrix_country)[colnames(NetMatrix_country) == "Usa"] <- "USA"
rownames(NetMatrix_country)[rownames(NetMatrix_country) == "Usa"] <- "USA"
colnames(NetMatrix_country)[colnames(NetMatrix_country) == "United Kingdom"] <- "UK"
rownames(NetMatrix_country)[rownames(NetMatrix_country) == "United Kingdom"] <- "UK"

# Set up circos parameters
circos.par(cell.padding = c(0, 0, 0, 0), track.margin = c(0, 0))

# Create chord diagram
chordDiagram(NetMatrix_country, annotationTrack = "grid", preAllocateTracks = 1)

# Label each sector with its name
circos.trackPlotRegion(track.index = 1, bg.border = NA, panel.fun = function(x, y) {
  xlim       = get.cell.meta.data("xlim")
  ylim       = get.cell.meta.data("ylim")
  sector.name= get.cell.meta.data("sector.index")
  circos.text(mean(xlim), ylim[1] + 0.2, sector.name, 
              facing = "clockwise", niceFacing = TRUE, adj = c(0, 0))
  circos.axis(h = "top", labels.cex = 0.5, major.tick.length = 0.2, 
              sector.index = sector.name, track.index = 2)
})

dev.off()
## png 
##   2

Chord diagram (no within-country collaborations)

Chord diagram illustration of collaborations across countries. Countries represent the location of the primary authors’ affiliated institution. Collaborations within countries are not shown.

jpeg(filename = here("figures", "chord_diagram_no_within_country.jpg"), width = 800, height = 800)

# Remove diagonal (within-country) collaborations
diag(NetMatrix_country) <- 0

# Create chord diagram
chordDiagram(NetMatrix_country, annotationTrack = "grid", preAllocateTracks = 1)

# Label each sector
circos.trackPlotRegion(track.index = 1, panel.fun = function(x, y) {
  xlim       = get.cell.meta.data("xlim")
  ylim       = get.cell.meta.data("ylim")
  sector.name= get.cell.meta.data("sector.index")
  circos.text(mean(xlim), ylim[1] + 0.2, sector.name, 
              facing = "clockwise", niceFacing = TRUE, adj = c(0, 0.5))
  circos.axis(h = "top", labels.cex = 0.5, major.tick.length = 0.2, 
              sector.index = sector.name, track.index = 2)
}, bg.border = NA)

dev.off()
## png 
##   2

Figure 4b

Chord diagram illustration of collaborations across continents. Continents represent the location of the primary authors’ affiliated institution. Collaborations within countries are not shown.

# Copy the country matrix into a “continent” matrix
NetMatrix_continent <- NetMatrix_country

# Rename countries to continents
colnames(NetMatrix_continent)[colnames(NetMatrix_continent) == "Usa"] <- "North America"
rownames(NetMatrix_continent)[rownames(NetMatrix_continent) == "Usa"] <- "North America"

colnames(NetMatrix_continent)[colnames(NetMatrix_continent) == "Spain"] <- "Europe"
rownames(NetMatrix_continent)[rownames(NetMatrix_continent) == "Spain"] <- "Europe"

# ... (remainder of your renaming for each country → continent) ...

# Collapse into summed continents matrix
merge_matrix   <- t(rowsum(t(NetMatrix_continent), group = colnames(NetMatrix_continent), na.rm = TRUE))
merge_matrix2  <- rowsum(merge_matrix, group = rownames(merge_matrix))
diag(merge_matrix2) <- 0  # remove diagonal if you do not want within-continent collaborations

# Create the chord diagram
chordDiagramFromMatrix(merge_matrix2)

# Optionally define color palette
my_colors <- c("#1B9E77", "#D95F02", "#7570B3", "#E6AB02")
my_colors <- rep(my_colors, length.out = ncol(merge_matrix2))

jpeg("figures/continent_chord_diagram.jpg", width = 25, height = 25, units = "cm", res = 300)
## Error in jpeg("figures/continent_chord_diagram.jpg", width = 25, height = 25, : unable to start jpeg() device
# Draw chord diagram with some styling
chordDiagram(merge_matrix2, 
             annotationTrack = "grid", 
             annotationTrackHeight = mm_h(7), 
             preAllocateTracks = 1,
             grid.col = my_colors)

# Add track to label each sector
circos.trackPlotRegion(track.index = 1, panel.fun = function(x, y) {
  xlim       = get.cell.meta.data("xlim")
  ylim       = get.cell.meta.data("ylim")
  sector.name= get.cell.meta.data("sector.index")
  circos.text(mean(xlim), ylim[1], sector.name, 
              facing = "bending.inside", niceFacing = TRUE, 
              adj = c(0.5, 1.75), col = "white", cex = 1.2)
}, bg.border = NA)

dev.off()
## null device 
##           1

Chord diagram of collaborations across continents

Chord diagram illustration of collaborations across disciplines. Disciplines have been allocated based on the Journal Citation Categories on Web of Science. Collaborations within disciplines are not shown.

# Copy the country matrix into a “continent” matrix
NetMatrix_continent <- NetMatrix_country

# Rename countries to continents
colnames(NetMatrix_continent)[colnames(NetMatrix_continent) == "Usa"] <- "North America"
rownames(NetMatrix_continent)[rownames(NetMatrix_continent) == "Usa"] <- "North America"

colnames(NetMatrix_continent)[colnames(NetMatrix_continent) == "Spain"] <- "Europe"
rownames(NetMatrix_continent)[rownames(NetMatrix_continent) == "Spain"] <- "Europe"

# ... (remainder of your renaming for each country → continent) ...

# Collapse into summed continents matrix
merge_matrix   <- t(rowsum(t(NetMatrix_continent), group = colnames(NetMatrix_continent), na.rm = TRUE))
merge_matrix2  <- rowsum(merge_matrix, group = rownames(merge_matrix))
diag(merge_matrix2) <- 0  # remove diagonal if you do not want within-continent collaborations

# Create the chord diagram
chordDiagramFromMatrix(merge_matrix2)

# Optionally define color palette
my_colors <- c("#1B9E77", "#D95F02", "#7570B3", "#E6AB02")
my_colors <- rep(my_colors, length.out = ncol(merge_matrix2))

jpeg("figures/continent_chord_diagram.jpg", width = 25, height = 25, units = "cm", res = 300)
## Error in jpeg("figures/continent_chord_diagram.jpg", width = 25, height = 25, : unable to start jpeg() device
# Draw chord diagram with some styling
chordDiagram(merge_matrix2, 
             annotationTrack = "grid", 
             annotationTrackHeight = mm_h(7), 
             preAllocateTracks = 1,
             grid.col = my_colors)

# Add track to label each sector
circos.trackPlotRegion(track.index = 1, panel.fun = function(x, y) {
  xlim       = get.cell.meta.data("xlim")
  ylim       = get.cell.meta.data("ylim")
  sector.name= get.cell.meta.data("sector.index")
  circos.text(mean(xlim), ylim[1], sector.name, 
              facing = "bending.inside", niceFacing = TRUE, 
              adj = c(0.5, 1.75), col = "white", cex = 1.2)
}, bg.border = NA)

dev.off()
## null device 
##           1
LS0tDQp0aXRsZTogIlNpeHR5IHllYXJzIHNpbmNlIFNpbGVudCBTcHJpbmc6IGEgbWFwIG9mIG1ldGEtYW5hbHlzZXMgb24gb3JnYW5vY2hsb3JpbmUgcGVzdGljaWRlcyByZXZlYWxzIHVyZ2VudCBuZWVkcyBmb3IgaW1wcm92aW5nIG1ldGhvZG9sb2dpY2FsIHF1YWxpdHkiDQphdXRob3I6ICJLeWxlIE1vcnJpc29uLCBDb3JhbGllIFdpbGxpYW1zLCBMb3JlbnpvIFJpY29sZmksIFllZmVuZyBZYW5nLCBNYWxnb3J6YXRhIExhZ2lzeiwgU2hpbmljaGkgTmFrYWdhd2EiIA0KZGF0ZTogIjIwMjMtMDMtMDkiDQpvdXRwdXQ6IA0KICBybWRmb3JtYXRzOjpkb3duY3V0ZToNCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgdG9jX2RlcHRoOiA0DQplZGl0b3Jfb3B0aW9uczogDQogIGNodW5rX291dHB1dF90eXBlOiBjb25zb2xlDQogIA0KLS0tDQpgYGB7ciwgaW5jbHVkZSA9IEZBTFNFfQ0Kcm0obGlzdCA9IGxzKCkpDQojIGtuaXRyIHNldHRpbmcNCmtuaXRyOjpvcHRzX2NodW5rJHNldCgNCiAgbWVzc2FnZSA9IEZBTFNFLA0KICB3YXJuaW5nID0gRkFMU0UsIA0KICBjYWNoZSA9IFRSVUUsDQogIGVycm9yID0gVFJVRSwgDQogIGVjaG89VFJVRQ0KKQ0KYGBgDQoNCg0KSW4gdGhpcyBSbWFya2Rvd24gZG9jdW1lbnQgd2UgcHJvdmlkZSB0aGUgZm9sbG93aW5nIHdvcmtmbG93OiAgIA0KDQotIFNlY3Rpb24gMDogVG8gZXhhbWluZSB0aGUgdm9sdW1lIGFuZCB0ZW1wb3JhbCB0cmVuZHMgb2YgZXhpc3RpbmcgbWV0YS1hbmFseXNlcyBvbiB0aGUgZWZmZWN0cyBvZiBvcmdhbm9jaGxvcmluZSBwZXN0aWNpZGVzDQoNCi0gU2VjdGlvbiAxOiBUbyBldmFsdWF0ZSB0aGUgbWV0aG9kb2xvZ2ljYWwgcGF0dGVybnMgYW5kIHF1YWxpdHkgb2YgZXhpc3RpbmcgbWV0YS1hbmFseXNlcyBzdHVkeWluZyB0aGUgZWZmZWN0cyBvZiBvcmdhbm9jaGxvcmluZSBwZXN0aWNpZGVzLg0KDQotIFNlY3Rpb24gMjogVG8gZXhwbG9yZSB0aGUgdmFyaW91cyBjaGFyYWN0ZXJpc3RpY3Mgb2YgdGhlIG9yZ2Fub2NobG9yaW5lIHBlc3RpY2lkZXMgbGl0ZXJhdHVyZSBzdWNoIGFzIHRoZSBwZXN0aWNpZGVzIHVzZWQsIHRoZSBpbXBhY3RzIGVsaWNpdGVkIGluIHJlc3BvbnNlIGFuZCB0aGUgc3ViamVjdHMgdGhhdCB3ZXJlIGludmVzdGlnYXRlZC4NCg0KLSBTZWN0aW9uIDM6IFRvIGludmVzdGlnYXRlIHRoZSByZXNlYXJjaCBvdXRwdXRzIGFjcm9zcyBkaWZmZXJlbnQgY291bnRyaWVzLCBjb250aW5lbnRzIGFuZCBkaXNjaXBsaW5lcywgYW5kIGludmVzdGlnYXRlIHRoZSBkZWdyZWUgb2YgY3Jvc3MtY291bnRyeSBjb2xsYWJvcmF0aW9uLg0KIA0KDQojIExvYWQgcGFja2FnZXMgYW5kIGRhdGENCiMjIExvYWQgcGFja2FnZXMgDQpgYGB7ciwgcmVzdWx0cz0iaGlkZSJ9DQpybShsaXN0ID0gbHMoKSkNCnBhY21hbjo6cF9sb2FkKHRpZHl2ZXJzZSwNCmhyYnJ0aGVtZXMsIA0KcGF0Y2h3b3JrLA0KaGVyZSwNCnN0cmluZ3IsDQprbml0ciwNCmZvcm1hdFIsDQpmb3JjYXRzLA0KZ2dwbG90MiwNCmJpYmxpb21ldHJpeCwNCm9yZGluYWwsDQppZ3JhcGgsDQpzdHJpbmdpLA0Kc3RyaW5nZGlzdCwNCmNpcmNsaXplLA0KZ2dhbGx1dmlhbCwNCmdncmFwaCwNCkNvbXBsZXhVcHNldCkNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UpDQoNCmBgYA0KDQoNCiMjIExvYWQgZGF0YQ0KTWFudWFsbHkgZXh0cmFjdGVkIHBpbG90IGRhdGEgaXMgc3RvcmVkIGluIGZpdmUgc2VwYXJhdGUgKiouY3N2KiogZmlsZXMgcmVwcmVzZW50aW5nIGRpZmZlcmVudCBhc3BlY3RzIG9mIHRoZSBkYXRhIChleHRyYWN0ZWQgdmlhIHN0cnVjdHVyZWQgcHJlZGVmaW5lZCBHb29nbGUgRm9ybXMgLSBvbmUgcGVyIHRhYmxlKS4gDQpCaWJsaW9ncmFwaGljIGRhdGEgcmVjb3JkcyBhcmUgZXhwb3J0ZWQgZnJvbSBTY29wdXMgKGluY2x1ZGluZyBjaXRlZCByZWZlcmVuY2VzIGZpZWxkKSBpbiAuYmliIGZvcm1hdCBhbmQgbG9jYWxseSBzYXZlZCBhcyAqKmJpYl9zY28uYmliKiouIA0KYGBge3IsICByZXN1bHRzPSJoaWRlIn0NCiMgTG9hZCBDU1YgZGF0YXNldHMNCnNkIDwtIHJlYWRfY3N2KGhlcmUoImRhdGEiLCAib2NwX3NybV9zdHVkeV9kZXRhaWxzLmNzdiIpKQ0Kb2NwIDwtIHJlYWRfY3N2KGhlcmUoImRhdGEiLCAib2NwX3NybV9vY3BfZGV0YWlscy5jc3YiKSkNCnN1YiA8LSByZWFkX2NzdihoZXJlKCJkYXRhIiwgIm9jcF9zcm1fc3ViamVjdF9kZXRhaWxzLmNzdiIpKQ0KaW0gPC0gcmVhZF9jc3YoaGVyZSgiZGF0YSIsICJvY3Bfc3JtX2ltcGFjdF9kZXRhaWxzLmNzdiIpKQ0Kc3AgPC0gcmVhZF9jc3YoaGVyZSgiZGF0YSIsICJvY3Bfc3JtX3NwZWNpZXNfZGV0YWlscy5jc3YiKSkNCnBvbCA8LSByZWFkX2NzdihoZXJlKCJkYXRhIiwgIm9jcF9zcm1fcG9saWN5LmNzdiIpKQ0KIyBMb2FkIEJpYlRlWCBkYXRhc2V0DQpiaWJfc2NvIDwtIGNvbnZlcnQyZGYoaGVyZSgiZGF0YSIsICJiaWJfc2NvLmJpYiIpLCBkYnNvdXJjZSA9ICJzY29wdXMiLCBmb3JtYXQgPSAiYmlidGV4IikNCg0KYGBgDQoNCiMgU2VjdGlvbiAwIA0KVG8gZXhhbWluZSB0aGUgdm9sdW1lIGFuZCB0ZW1wb3JhbCB0cmVuZHMgb2YgZXhpc3RpbmcgbWV0YS1hbmFseXNlcyBvbiB0aGUgZWZmZWN0cyBvZiBvcmdhbm9jaGxvcmluZSBwZXN0aWNpZGVzDQoNCiMjIEZpZ3VyZSAxIA0KQSkgQmFyIGNoYXJ0IHNob3dpbmcgdGhlIGFubnVhbCBudW1iZXIgb2YgbWV0YS1hbmFseXNlcyBzeW50aGVzaXNpbmcgcmVzZWFyY2ggb24gdGhlIGltcGFjdHMgb2Ygb3JnYW5vY2hsb3JpbmUgcGVzdGljaWRlcywgY2F0ZWdvcmlzZWQgYnkgZGlmZmVyZW50IHN1YmplY3RzIG9mIGV4cG9zdXJlLiANCkIpIEFyZWEgZ3JhcGggc2hvd2luZyB0aGUgY3VtdWxhdGl2ZSB0aW1lIHRyZW5kcyBvZiBtZXRhLWFuYWx5c2VzIHN5bnRoZXNpc2luZyByZXNlYXJjaCBvbiB0aGUgaW1wYWN0cyBvZiBvcmdhbm9jaGxvcmluZSBwZXN0aWNpZGVzLCBjYXRlZ29yaXNlZCBieSBkaWZmZXJlbnQgc3ViamVjdHMgb2YgZXhwb3N1cmUuDQpDKSBCYXIgY2hhcnQgc2hvd2luZyB0aGUgYW5udWFsIG51bWJlciBvZiBwb2xpY3kgY2l0YXRpb25zIG9uIHRoZSBpbmNsdWRlZCBtZXRhLWFuYWx5c2lzIGFuYWx5c2VzIHN5bnRoZXNpc2luZyByZXNlYXJjaCBvbiB0aGUgaW1wYWN0cyBvZiBvcmdhbm9jaGxvcmluZSBwZXN0aWNpZGVzLCBjYXRlZ29yaXNlZCBieSBwb2xpY3kgdG9waWNzDQpEKSBBcmVhIGdyYXBoIHNob3dpbmcgdGhlIGN1bXVsYXRpdmUgdGltZSB0cmVuZHMgb2YgcG9saWN5IGNpdGF0aW9ucyBvbiB0aGUgaW5jbHVkZWQgbWV0YS1hbmFseXNpcyBhbmFseXNlcyBzeW50aGVzaXNpbmcgcmVzZWFyY2ggb24gdGhlIGltcGFjdHMgb2Ygb3JnYW5vY2hsb3JpbmUgcGVzdGljaWRlcywgY2F0ZWdvcmlzZWQgYnkgcG9saWN5IHRvcGljcw0KYGBge3IsIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD0xMn0NCiMgSm9pbiB0aGUgc3R1ZHkgYW5kIHN1YmplY3QgZGF0YXNldHMNCnNkX3N1YiA8LSBsZWZ0X2pvaW4oc2QsIHN1YiwgYnkgPSAic3R1ZHlfaWQiKQ0KDQojIENvdW50IHRoZSBudW1iZXIgb2YgcHVibGljYXRpb25zIHBlciB5ZWFyIGFuZCBjYWxjdWxhdGUgY3VtdWxhdGl2ZSBzdW0NCnNkMSA8LSBzZCAlPiUNCiAgY291bnQocHVibGljYXRpb25feWVhcikgJT4lDQogIG11dGF0ZShuX2N1bXVsYXRpdmUgPSBjdW1zdW0obikpDQoNCiMgQ3VzdG9tIHRoZW1lIGVuc3VyaW5nIGNvbnNpc3RlbnQgZm9ybWF0dGluZw0KdGhlbWVfY291bnQgPC0gZnVuY3Rpb24oKSB7DQogIHRoZW1lX21pbmltYWwoKSArDQogICAgdGhlbWUoDQogICAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiZ3JheSIsIGxpbmV0eXBlID0gImRhc2hlZCIpLA0KICAgICAgcGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgYXhpcy5saW5lLnggPSBlbGVtZW50X2xpbmUoc2l6ZSA9IDEuMiksDQogICAgICBheGlzLmxpbmUueSA9IGVsZW1lbnRfbGluZShzaXplID0gMS4yKSwNCiAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIpLA0KICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCwgZmFjZSA9ICJib2xkIiksDQogICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHNpemUgPSAxNSwgY29sb3IgPSAiIzY2NjY2NiIpLA0KICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwLCBjb2xvciA9ICIjNjY2NjY2IiksDQogICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIgICMgSGlkZSBsZWdlbmQgYnkgZGVmYXVsdA0KICAgICkNCn0NCg0KIyBTZXQgZml4ZWQgeWVhciByYW5nZQ0KbWluX3llYXIgPC0gMTk5Mw0KbWF4X3llYXIgPC0gMjAyMg0KDQpmaWcxYSA8LSBzZF9zdWIgJT4lDQogIG11dGF0ZShzdWJqZWN0cyA9IHN0cnNwbGl0KHN1YmplY3QsICIsXFxzKyIpKSAlPiUNCiAgdW5uZXN0KHN1YmplY3RzKSAlPiUNCiAgY291bnQocHVibGljYXRpb25feWVhciwgc3ViamVjdHMpICU+JQ0KICBncm91cF9ieShzdWJqZWN0cyA9IHJlb3JkZXIoc3ViamVjdHMsIG4pKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gcHVibGljYXRpb25feWVhciwgeSA9IG4sIGZpbGwgPSBzdWJqZWN0cykpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gInN0YWNrIiwgYWxwaGEgPSAwLjcpICsNCiAgZ2VvbV90ZXh0KA0KICAgIGFlcyhsYWJlbCA9IG4pLA0KICAgIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjYpLA0KICAgIGZvbnRmYWNlID0gImJvbGQiLCANCiAgICBjb2xvciA9ICJ3aGl0ZSIsIA0KICAgIHNpemUgPSA2LCANCiAgICBoanVzdCA9IDAuNA0KICApICsNCiAgc2NhbGVfeF9jb250aW51b3VzKA0KICAgIGJyZWFrcyA9IHNlcShtaW5feWVhciwgbWF4X3llYXIsIGJ5ID0gMSksDQogICAgbGltaXRzID0gYyhtaW5feWVhciwgbWF4X3llYXIgKyAxKSwgICMgQWRkIDEgeWVhciBiZXlvbmQgbWF4X3llYXINCiAgICBleHBhbmQgPSBleHBhbnNpb24oMCwgMCkgICAgICAgICAgICAjIE5vIGV4dHJhIGdhcCBhdCBlZGdlcw0KICApICsNCiAgc2NhbGVfeV9jb250aW51b3VzKCJBbm51YWwgQXJ0aWNsZSBDb3VudCIsIGxpbWl0cyA9IGMoMCwgMTUpKSArDQogICMgVXNlIHBsb3RtYXRoIGV4cHJlc3Npb24gdG8gbWFrZSB0aGUgdGl0bGUgYm9sZCBhbmQgdW5kZXJsaW5lZA0KICBsYWJzKA0KICAgIHRpdGxlID0gZXhwcmVzc2lvbihib2xkKHVuZGVybGluZSgiQXJ0aWNsZXMiKSkpLA0KICAgIHkgPSAiQXJ0aWNsZSBDb3VudCIsIA0KICAgIHRhZyA9ICJBIiwgDQogICAgZmlsbCA9ICJTdWJqZWN0cyINCiAgKSArDQogIHRoZW1lX2NvdW50KCkgKw0KICB0aGVtZSgNCiAgICAjIE1ha2UgdGl0bGUgYmlnZ2VyDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjYpLA0KICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAsIDEpLA0KICAgIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygwLCAxKSwNCiAgICBsZWdlbmQuYm94Lmp1c3QgPSAibGVmdCIsDQogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBmYWNlID0gImJvbGQiKSwNCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBmYWNlID0gImJvbGQiKQ0KICApICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpICsNCiAgZ3VpZGVzKA0KICAgIGZpbGwgPSBndWlkZV9sZWdlbmQoDQogICAgICB0aXRsZSA9ICJTdWJqZWN0cyIsIA0KICAgICAgb3ZlcnJpZGUuYWVzID0gbGlzdChhbHBoYSA9IDAuNywgc2l6ZSA9IDgpDQogICAgKQ0KICApDQoNCiMgQ3JlYXRlIHRoZSBjdW11bGF0aXZlIGNvdW50IHBsb3QgZm9yIGFydGljbGVzIChmaWcxYikgLSBIaWRlcyBsZWdlbmQNCmZpZzFiIDwtIHNkX3N1YiAlPiUNCiAgbXV0YXRlKHN1YmplY3RzID0gc3Ryc3BsaXQoc3ViamVjdCwgIixcXHMrIikpICU+JQ0KICB1bm5lc3Qoc3ViamVjdHMpICU+JQ0KICBjb3VudChwdWJsaWNhdGlvbl95ZWFyLCBzdWJqZWN0cykgJT4lDQogIGdyb3VwX2J5KHN1YmplY3RzID0gcmVvcmRlcihzdWJqZWN0cywgbikpICU+JQ0KICBtdXRhdGUobl9jdW11bGF0aXZlID0gY3Vtc3VtKG4pKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gcHVibGljYXRpb25feWVhciwgeSA9IG5fY3VtdWxhdGl2ZSwgZmlsbCA9IHN1YmplY3RzKSkgKw0KICBnZW9tX2FyZWEoc2l6ZSA9IDEuMiwgYWxwaGEgPSAwLjcpICsgICMgRW5zdXJpbmcgY29uc2lzdGVudCBhbHBoYQ0KICBzY2FsZV95X2NvbnRpbnVvdXMoIkN1bXVsYXRpdmUgQXJ0aWNsZSBDb3VudCIsIGxpbWl0cyA9IGMoMCwgMTI1KSwgZXhwYW5kID0gZXhwYW5zaW9uKDAsIDApKSArDQogIHNjYWxlX3hfY29udGludW91cygNCiAgICBicmVha3MgPSBzZXEobWluKHNkX3N1YiRwdWJsaWNhdGlvbl95ZWFyKSwgbWF4KHNkX3N1YiRwdWJsaWNhdGlvbl95ZWFyKSwgYnkgPSAxKSwgDQogICAgZXhwYW5kID0gZXhwYW5zaW9uKDAsMCkNCiAgKSArICANCiAgbGFicyh4ID0gIlllYXIiLCB5ID0gIkN1bXVsYXRpdmUgQXJ0aWNsZSBDb3VudCIsIHRhZyA9ICJCIikgKw0KICB0aGVtZV9jb3VudCgpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpICsNCiAgdGhlbWUoDQogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiICAjIFJlbW92ZSBsZWdlbmQgZnJvbSB0aGlzIHBsb3QNCiAgKQ0KDQpmaWcxYyA8LSBnZ3Bsb3QoDQogIHBvbCAlPiUNCiAgICBmaWx0ZXIoIWlzLm5hKHBvbGljeV90aXRsZSkpICU+JQ0KICAgIG11dGF0ZShwb2xpY3lfdG9waWMgPSBzdHJzcGxpdChwb2xpY3lfdG9waWMsICI7XFxzKyIpKSAlPiUNCiAgICB1bm5lc3QocG9saWN5X3RvcGljKSAlPiUNCiAgICBncm91cF9ieShwb2xpY3lfdG9waWMpICU+JQ0KICAgIG11dGF0ZSh0b3RhbF9jb3VudCA9IG4oKSkgJT4lDQogICAgdW5ncm91cCgpICU+JQ0KICAgIG11dGF0ZShwb2xpY3lfdG9waWMgPSBpZl9lbHNlKHRvdGFsX2NvdW50IDwgNywgIk90aGVyIiwgcG9saWN5X3RvcGljKSkgJT4lDQogICAgZmlsdGVyKHBvbGljeV95ZWFyIDw9IDIwMjMpICU+JQ0KICAgIGNvdW50KHBvbGljeV95ZWFyLCBwb2xpY3lfdG9waWMpICU+JQ0KICAgIGNvbXBsZXRlKA0KICAgICAgcG9saWN5X3llYXIgPSAxOTkzOjIwMjIsDQogICAgICBwb2xpY3lfdG9waWMgPSB1bmlxdWUocG9saWN5X3RvcGljKSwNCiAgICAgIGZpbGwgPSBsaXN0KG4gPSAwKQ0KICAgICksDQogIGFlcyh4ID0gcG9saWN5X3llYXIsIHkgPSBuLCBmaWxsID0gcG9saWN5X3RvcGljKQ0KKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJzdGFjayIsIGFscGhhID0gMC43KSArDQogIGdlb21fdGV4dCgNCiAgICBhZXMobGFiZWwgPSBpZmVsc2UobiA+IDEsIG4sICIiKSksDQogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNiksDQogICAgZm9udGZhY2UgPSAiYm9sZCIsDQogICAgY29sb3IgPSAid2hpdGUiLA0KICAgIHNpemUgPSA2LA0KICAgIGhqdXN0ID0gMC40DQogICkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoDQogICAgYnJlYWtzID0gMTk5MzoyMDIyLCAgICAgICAgICAgICAgDQogICAgbGltaXRzID0gYygxOTkzLCAyMDIzKSwgICAgICAgICAgDQogICAgZXhwYW5kID0gZXhwYW5zaW9uKDAsIDApDQogICkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoDQogICAgIkFubnVhbCBQb2xpY3kgQ2l0YXRpb25zIiwgDQogICAgbGltaXRzID0gYygwLCA0MCksDQogICAgZXhwYW5kID0gZXhwYW5zaW9uKDAsIDApDQogICkgKw0KICBsYWJzKA0KICAgICMgVXNlIHBsb3RtYXRoIGV4cHJlc3Npb24gaGVyZSBhcyB3ZWxsDQogICAgdGl0bGUgPSBleHByZXNzaW9uKGJvbGQodW5kZXJsaW5lKCJQb2xpY3kiKSkpLA0KICAgIHggPSAiWWVhciIsDQogICAgeSA9ICJBbm51YWwgUG9saWN5IENpdGF0aW9ucyIsIA0KICAgIHRhZyA9ICJDIiwgDQogICAgZmlsbCA9ICJQb2xpY3kgVG9waWNzIg0KICApICsNCiAgdGhlbWVfY291bnQoKSArDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiKSArDQogIHRoZW1lKA0KICAgICMgTWFrZSB0aXRsZSBiaWdnZXINCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyNiksDQogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC4wLCAxKSwNCiAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9IGMoMCwgMSksDQogICAgbGVnZW5kLmJveC5qdXN0ID0gImxlZnQiLA0KICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgZmFjZSA9ICJib2xkIiksDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiwgZmFjZSA9ICJib2xkIikNCiAgKSArDQogIGd1aWRlcygNCiAgICBmaWxsID0gZ3VpZGVfbGVnZW5kKA0KICAgICAgdGl0bGUgPSAiVG9waWNzIiwNCiAgICAgIG92ZXJyaWRlLmFlcyA9IGxpc3QoYWxwaGEgPSAwLjcsIHNpemUgPSA4KQ0KICAgICkNCiAgKQ0KDQojIENyZWF0ZSBmaWcxZA0KZmlnMWQgPC0gcG9sICU+JQ0KICBmaWx0ZXIoIWlzLm5hKHBvbGljeV90aXRsZSkpICU+JQ0KICBtdXRhdGUocG9saWN5X3RvcGljID0gc3Ryc3BsaXQocG9saWN5X3RvcGljLCAiO1xccysiKSkgJT4lDQogIHVubmVzdChwb2xpY3lfdG9waWMpICU+JQ0KICBncm91cF9ieShwb2xpY3lfdG9waWMpICU+JQ0KICBtdXRhdGUodG90YWxfY291bnQgPSBuKCkpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIG11dGF0ZShwb2xpY3lfdG9waWMgPSBpZl9lbHNlKHRvdGFsX2NvdW50IDwgNywgIk90aGVyIiwgcG9saWN5X3RvcGljKSkgJT4lDQogIGZpbHRlcihwb2xpY3lfeWVhciA8IDIwMjMpICU+JQ0KICBjb3VudChwb2xpY3lfeWVhciwgcG9saWN5X3RvcGljKSAlPiUNCiAgY29tcGxldGUoDQogICAgcG9saWN5X3llYXIgPSAxOTkzOjIwMjIsDQogICAgcG9saWN5X3RvcGljID0gdW5pcXVlKHBvbGljeV90b3BpYyksDQogICAgZmlsbCA9IGxpc3QobiA9IDApDQogICkgJT4lDQogIGdyb3VwX2J5KHBvbGljeV90b3BpYykgJT4lDQogIGFycmFuZ2UocG9saWN5X3llYXIsIC5ieV9ncm91cCA9IFRSVUUpICU+JQ0KICBtdXRhdGUobl9jdW11bGF0aXZlID0gY3Vtc3VtKG4pKSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBwb2xpY3lfeWVhciwgeSA9IG5fY3VtdWxhdGl2ZSwgZmlsbCA9IHBvbGljeV90b3BpYykpICsNCiAgZ2VvbV9hcmVhKHNpemUgPSAxLjIsIGFscGhhID0gMC43KSArDQogIHNjYWxlX3lfY29udGludW91cygNCiAgICAiQ3VtdWxhdGl2ZSBQb2xpY3kgQ2l0YXRpb25zIiwgDQogICAgbGltaXRzID0gYygwLCAyNTApLCANCiAgICBleHBhbmQgPSBleHBhbnNpb24oMCwgMCkNCiAgKSArDQogIHNjYWxlX3hfY29udGludW91cygNCiAgICBicmVha3MgPSAxOTkzOjIwMjIsDQogICAgZXhwYW5kID0gZXhwYW5zaW9uKDAsIDApDQogICkgKw0KICBsYWJzKA0KICAgIHggPSAiWWVhciIsDQogICAgeSA9ICJDdW11bGF0aXZlIFBvbGljeSBDaXRhdGlvbnMiLCANCiAgICB0YWcgPSAiRCINCiAgKSArDQogIHRoZW1lX2NvdW50KCkgKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIikgKw0KICB0aGVtZSgNCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSINCiAgKQ0KDQojIENvbWJpbmUgcGxvdHMsIGVuc3VyaW5nIHRoZSBsZWdlbmQgb25seSBhcHBlYXJzIGluIGZpZzFhIGFuZCBmaWcxYw0KZmlnMSA8LSBmaWcxYSAvIGZpZzFiIC8gZmlnMWMgLyBmaWcxZA0KDQojIERpc3BsYXkgdGhlIGZpbmFsIGNvbWJpbmVkIHBsb3QNCmZpZzENCg0KDQojIFNhdmUgdGhlIGZpbmFsIGZpZ3VyZQ0KZ2dzYXZlKA0KICBoZXJlKCJmaWd1cmVzIiwgImZpZzEucGRmIiksIA0KICB3aWR0aCA9IDE2LCBoZWlnaHQgPSAyNCwgdW5pdHMgPSAiY20iLCANCiAgc2NhbGUgPSAyLCBkcGkgPSA4MDANCikNCg0KIyBDb21iaW5lIHBsb3RzLCBlbnN1cmluZyB0aGUgbGVnZW5kIG9ubHkgYXBwZWFycyBpbiBmaWcxYQ0KZmlnMSA8LSBmaWcxYSAvIGZpZzFiIC8gZmlnMWMgLyBmaWcxZA0KDQojIERpc3BsYXkgdGhlIGZpbmFsIGNvbWJpbmVkIHBsb3QNCmZpZzENCg0KIyBTYXZlIHRoZSBmaW5hbCBmaWd1cmUNCiMgZ2dzYXZlKGhlcmUoImZpZ3VyZXMiLCAiZmlnMS5wZGYiKSwgd2lkdGggPSAxNiwgaGVpZ2h0ID0gMjQsIHVuaXRzID0gImNtIiwgc2NhbGUgPSAyLCBkcGkgPSA4MDApDQojIGdnc2F2ZShoZXJlKCJmaWd1cmVzIiwgImZpZzEuanBnIiksIHdpZHRoID0gMTYsIGhlaWdodCA9IDI0LCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KDQpgYGANCg0KIyMgUG9saWN5IGNvdW50cnkgYmFyIHBsb3QNCkJhciBjaGFydCBzaG93aW5nIHRoZSBhbm51YWwgbnVtYmVyIG9mIHBvbGljeSBjaXRhdGlvbnMgb24gdGhlIGluY2x1ZGVkIG1ldGEtYW5hbHlzaXMgYW5hbHlzZXMgc3ludGhlc2lzaW5nIHJlc2VhcmNoIG9uIHRoZSBpbXBhY3RzIG9mIG9yZ2Fub2NobG9yaW5lIHBlc3RpY2lkZXMsIGNhdGVnb3Jpc2VkIGJ5IGNvdW50cnkNCmBgYHtyfQ0KcG9saWN5X2NvdW50cnkgPC0gZ2dwbG90KA0KICBwb2wgJT4lDQogICAgIyAxKSBSZW1vdmUgcm93cyB3aXRoIE5BIHBvbGljeV90aXRsZQ0KICAgIGZpbHRlcighaXMubmEocG9saWN5X3RpdGxlKSkgJT4lDQogICAgIyAyKSBTcGxpdCBtdWx0aS1jb3VudHJ5IHN0cmluZ3Mgb24gc2VtaWNvbG9uIGFuZCB1bm5lc3QNCiAgICBtdXRhdGUocG9saWN5X2NvdW50cnkgPSBzdHJzcGxpdChwb2xpY3lfY291bnRyeSwgIjtcXHMrIikpICU+JQ0KICAgIHVubmVzdChwb2xpY3lfY291bnRyeSkgJT4lDQogICAgIyAzKSBMdW1wIGFueSBjb3VudHJ5IHVzZWQgZmV3ZXIgdGhhbiA3IHRpbWVzIG92ZXJhbGwNCiAgICBncm91cF9ieShwb2xpY3lfY291bnRyeSkgJT4lDQogICAgbXV0YXRlKHRvdGFsX2NvdW50ID0gbigpKSAlPiUNCiAgICB1bmdyb3VwKCkgJT4lDQogICAgbXV0YXRlKHBvbGljeV9jb3VudHJ5ID0gaWZfZWxzZSh0b3RhbF9jb3VudCA8IDUsICJPdGhlciIsIHBvbGljeV9jb3VudHJ5KSkgJT4lDQogICAgIyA0KSBLZWVwIG9ubHkgeWVhcnMgPD0gMjAyMw0KICAgIGZpbHRlcihwb2xpY3lfeWVhciA8PSAyMDIzKSAlPiUNCiAgICAjIDUpIENvdW50IG51bWJlciBvZiBwb2xpY2llcyBwZXIgKHllYXIsIGNvdW50cnkpDQogICAgY291bnQocG9saWN5X3llYXIsIHBvbGljeV9jb3VudHJ5KSAlPiUNCiAgICAjIDYpIENvbXBsZXRlIG1pc3NpbmcgKHllYXIsIGNvdW50cnkpIGNvbWJvcyBmcm9tIDE5OTMgdG8gMjAyMiB3aXRoIG4gPSAwDQogICAgY29tcGxldGUoDQogICAgICBwb2xpY3lfeWVhciA9IDE5OTM6MjAyMiwNCiAgICAgIHBvbGljeV9jb3VudHJ5ID0gdW5pcXVlKHBvbGljeV9jb3VudHJ5KSwNCiAgICAgIGZpbGwgPSBsaXN0KG4gPSAwKQ0KICAgICksDQogIGFlcyh4ID0gcG9saWN5X3llYXIsIHkgPSBuLCBmaWxsID0gcG9saWN5X2NvdW50cnkpDQopICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gInN0YWNrIiwgYWxwaGEgPSAwLjcpICsNCiAgZ2VvbV90ZXh0KA0KICAgIGFlcyhsYWJlbCA9IGlmZWxzZShuID4gMCwgbiwgIiIpKSwNCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC42KSwNCiAgICBmb250ZmFjZSA9ICJib2xkIiwgY29sb3IgPSAid2hpdGUiLCBzaXplID0gNiwgaGp1c3QgPSAwLjQNCiAgKSArDQogIHNjYWxlX3hfY29udGludW91cygNCiAgICBicmVha3MgPSAxOTkzOjIwMjIsICAgICAgICAgICAgICANCiAgICBsaW1pdHMgPSBjKDE5OTMsIDIwMjMpLCAgICAgICAgICANCiAgICBleHBhbmQgPSBleHBhbnNpb24oMCwgMCkNCiAgKSArDQogIHNjYWxlX3lfY29udGludW91cygNCiAgICAiQW5udWFsIFBvbGljeSBDaXRhdGlvbnMiLCANCiAgICBsaW1pdHMgPSBjKDAsIDQwKSwgICAgICAjIEFkanVzdCBpZiB5b3Ugd2FudCBhIGRpZmZlcmVudCBtYXggb24gdGhlIHktYXhpcw0KICAgIGV4cGFuZCA9IGV4cGFuc2lvbigwLCAwKQ0KICApICsNCiAgbGFicygNCiAgICB4ID0gIlllYXIiLA0KICAgIHkgPSAiQW5udWFsIFBvbGljeSBDaXRhdGlvbnMiLCANCiAgICBmaWxsID0gIlBvbGljeSBDb3VudHJpZXMiDQogICkgKw0KICB0aGVtZV9jb3VudCgpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpICsNCiAgdGhlbWUoDQogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC4wLCAxKSwgICAjIFRvcC1sZWZ0DQogICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSBjKDAsIDEpLA0KICAgIGxlZ2VuZC5ib3guanVzdCA9ICJsZWZ0Ig0KICApICsNCiAgZ3VpZGVzKA0KICAgIGZpbGwgPSBndWlkZV9sZWdlbmQoDQogICAgICB0aXRsZSA9ICJQb2xpY3kgQ291bnRyaWVzIiwNCiAgICAgIG92ZXJyaWRlLmFlcyA9IGxpc3QoYWxwaGEgPSAwLjcsIHNpemUgPSA4KQ0KICAgICkNCiAgKQ0KDQojIGdnc2F2ZShoZXJlKCJmaWd1cmVzIiwgInBvbGljeV9jb3VudHJ5LnBkZiIpLCB3aWR0aCA9IDE2LCBoZWlnaHQgPSAxMCwgdW5pdHMgPSAiY20iLCBzY2FsZSA9IDIsIGRwaSA9IDgwMCkNCiMgZ2dzYXZlKGhlcmUoImZpZ3VyZXMiLCAicG9saWN5X2NvdW50cnkuanBnIiksIHdpZHRoID0gMTYsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KDQpgYGANCg0KIyMgDQpDcmVhdGUgYSBzdGFuZGFyZCB0aGVtZSBmb3IgdGhlIHN1cHBsZW1lbnRhcnkgcGxvdHMNCmBgYHtyfQ0Kb3JnYW5vY2hsb3JUSEVNRSA8LSBmdW5jdGlvbigpIHsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoDQogICAgdGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMwKSwNCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMzApLA0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCksDQogICAgYXhpcy5saW5lLnggPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiZ3JheSIsIHNpemUgPSAzKSwNCiAgICBheGlzLmxpbmUueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgIHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICAgIA0KfQ0KDQpgYGANCg0KIyMgQWx0ZXJuYXRpdmUgdGltZSB0cmVuZHMNCkEpIEJhciBjaGFydCBzaG93aW5nIHRoZSBhbm51YWwgbnVtYmVyIG9mIHB1Ymxpc2hlZCBtZXRhLWFuYWx5c2VzIHN5bnRoZXNpc2luZyByZXNlYXJjaCBvbiB0aGUgaW1wYWN0cyBvZiBvcmdhbm9jaGxvcmluZSBwZXN0aWNpZGVzLiAgDQpCKSBMaW5lIGdyYXBoIHNob3dpbmcgdGhlIGN1bXVsYXRpdmUgdGltZSB0cmVuZHMgb2YgbWV0YS1hbmFseXNlcyBzeW50aGVzaXNpbmcgcmVzZWFyY2ggb24gdGhlIGltcGFjdHMgb2Ygb3JnYW5vY2hsb3JpbmUgcGVzdGljaWRlcy4NCmBgYHtyLCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9MTJ9DQojIENyZWF0ZSB0aGUgYW5udWFsIENvdW50IFBsb3QNCmFubnVhbF9hcnRpY2xlX2NvdW50IDwtIHNkMSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gcHVibGljYXRpb25feWVhciwgeSA9IG4pKSArDQogICAgZ2VvbV9jb2woZmlsbCA9ICIjMWI5ZTc3IiwgYWxwaGEgPSAwLjcpICsNCiAgICBnZW9tX3RleHQoYWVzKGxhYmVsID0gbiksIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjYpLCANCiAgICAgICAgICAgICAgZm9udGZhY2UgPSAiYm9sZCIsIGNvbG9yID0gIndoaXRlIiwgc2l6ZSA9IDYsIGhqdXN0ID0gMC40KSArDQogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcShtaW4oc2QxJHB1YmxpY2F0aW9uX3llYXIpLCBtYXgoc2QxJHB1YmxpY2F0aW9uX3llYXIpLCBieSA9IDEpLCANCiAgICAgICAgICAgICAgICAgICAgICAgZXhwYW5kID0gZXhwYW5zaW9uKDAsMSkpICsNCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoIkFubnVhbCBBcnRpY2xlIENvdW50IiwgbGltaXRzID0gYygwLDE1KSkgKw0KICAgIGxhYnMoeCA9ICJZZWFyIiwgdGFnID0gIkEiKSArDQogICAgdGhlbWVfY291bnQoKSArDQogICAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKQ0KDQoNCiMgQ3JlYXRlIHRoZSBjdW11bGF0aXZlIENvdW50IFBsb3QNCmN1bV9hcnRpY2xlX2NvdW50IDwtIHNkMSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gcHVibGljYXRpb25feWVhciwgeSA9IG5fY3VtdWxhdGl2ZSkpICsNCiAgICBnZW9tX2xpbmUoY29sb3IgPSAiIzc1NzBiMyIsIHNpemUgPSAxLCBsaW5ldHlwZSA9ICJzb2xpZCIpICsNCiAgICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA2LCBmaWxsID0gIiM3NTcwYjMiLCBzdHJva2UgPSAwKSArDQogICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IG5fY3VtdWxhdGl2ZSksIGhqdXN0ID0gMC4yLCB2anVzdCA9IC0xLCBzaXplID0gNiwgY29sb3IgPSAiYmxhY2siKSArDQogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcShtaW4oc2QxJHB1YmxpY2F0aW9uX3llYXIpLCBtYXgoc2QxJHB1YmxpY2F0aW9uX3llYXIpLCBieSA9IDEpLCANCiAgICAgICAgICAgICAgICAgICAgICAgZXhwYW5kID0gZXhwYW5zaW9uKDAsMSkpICsNCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoIkN1bXVsYXRpdmUgQXJ0aWNsZSBDb3VudCIsIGxpbWl0cyA9IGMoMCwxMjApKSArDQogICAgbGFicyh4ID0gIlllYXIiLCB0YWcgPSAiQiIpICsNCiAgICB0aGVtZV9jb3VudCgpDQoNCiMgQ29tYmluZSB0aGUgdHdvIHBsb3RzDQphbHRfYXJ0aWNsZV9jb3VudCA8LSBhbm51YWxfYXJ0aWNsZV9jb3VudCAvIGN1bV9hcnRpY2xlX2NvdW50DQoNCmFsdF9hcnRpY2xlX2NvdW50DQoNCiMgZ2dzYXZlKGhlcmUoImZpZ3VyZXMiLCAiYWx0X2FydGljbGVfY291bnQucGRmIiksIHdpZHRoID0gMTYsIGhlaWdodCA9IDEyLCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJhbHRfYXJ0aWNsZV9jb3VudC5qcGciKSwgd2lkdGggPSAxNiwgaGVpZ2h0ID0gMTIsIHVuaXRzID0gImNtIiwgc2NhbGUgPSAyLCBkcGkgPSA4MDApDQoNCmBgYA0KDQojIFNlY3Rpb24gMQ0KVG8gZXZhbHVhdGUgdGhlIG1ldGhvZG9sb2dpY2FsIHF1YWxpdHkgYW5kIHBhdHRlcm5zIG9mIGV4aXN0aW5nIG1ldGEtYW5hbHlzZXMgc3R1ZHlpbmcgdGhlIGVmZmVjdHMgb2Ygb3JnYW5vY2hsb3JpbmUgcGVzdGljaWRlcy4gDQoNCiMjIEZpZ3VyZSAyDQpUaGUgbWV0aG9kb2xvZ2ljYWwgYW5kIHJlcG9ydGluZyBxdWFsaXR5IG9mIG1ldGEtYW5hbHlzZXMgYWNjb3JkaW5nIHRvIENFRVNBVCB2LiAyLjEgKFdvb2Rjb2NrIGV0IGFsLiwgMjAxNCkuIFNjb3JlcyBhcmUgcmVwcmVzZW50ZWQgYnkgdGhlIGZvbGxvd2luZyBjb2xvdXJzOiBnb2xkIGlzIHJlZ2FyZGVkIGFzIHRoZSBoaWdoZXN0IChiZXN0KSBzY29yZSwgZ3JlZW4gaXMgc2Vjb25kIGhpZ2hlc3Qgc2NvcmUsIGFtYmVyIGlzIHNlY29uZC1sb3dlc3Qgc2NvcmUsIGFuZCByZWQgaXMgdGhlIGxvd2VzdCAod29yc3QpIHNjb3JlLiBUaGUgdG90YWwgY291bnRzIG9mIHN0dWRpZXMgYWxsb2NhdGVkIHRvIGVhY2ggc2NvcmUgYXJlIHNob3duIGluIGVhY2ggYmFyLiBBbGwgQ0VFU0FUIHYuIDIuMSBpdGVtcywgYWxvbmcgd2l0aCBvdXIgaW50ZXJwcmV0YXRpb24sIGFyZSBwcm92aWRlZCBpbiBTdXBwbGVtZW50YXJ5IEZpbGUgMi4gDQoNCiMjIEZpZ3VyZSAyYQ0KQ0VFU0FUIHNjb3JlcyBmb3IgODMgYXNzZXNzZWQgbWV0YS1hbmFseXNlcyANCmBgYHtyLCBmaWcud2lkdGg9MjUsIGZpZy5oZWlnaHQ9MTV9DQojIFN0YXJ0IHRoZSBkYXRhIG1hbmlwdWxhdGlvbg0KcGVyY2VudF9jZWVzYXRfc2NvcmUgPC0gc2QgJT4lDQogIGZpbHRlcighaXMubmEoYXV0aG9yX3llYXIpKSAlPiUNCiAgc2VsZWN0KHN0dWRpZXMgPSBhdXRob3JfeWVhciwgc3RhcnRzX3dpdGgoIkNFRSIpKSAlPiUNCiAgbmEub21pdCgpICU+JQ0KICBwaXZvdF9sb25nZXIoY29scyA9IC1zdHVkaWVzLCBuYW1lc190byA9ICJxdWVzdGlvbiIsIHZhbHVlc190byA9ICJzY29yZSIpICU+JQ0KICBncm91cF9ieShxdWVzdGlvbiwgc2NvcmUpICU+JQ0KICBzdW1tYXJpc2UobiA9IG4oKSwgLmdyb3VwcyA9ICdkcm9wJykgJT4lDQogIG11dGF0ZShwZXJjZW50ID0gKG4vc3VtKG4pKSoxMDAsIA0KICAgICAgICAgYWNyb3NzKGMocXVlc3Rpb24sIHNjb3JlKSwgYXMuZmFjdG9yKSwNCiAgICAgICAgIHF1ZXN0aW9uID0gZmN0X3JlY29kZShxdWVzdGlvbiwgDQogICAgICAgICAgIGAxLjEgQXJlIHRoZSBlbGVtZW50cyBvZiB0aGUgcmV2aWV3IHF1ZXN0aW9uIGNsZWFyP2AgPSAiQ0VFU0FUMl8xLjEiLA0KICAgICAgICAgICBgMi4xIElzIHRoZXJlIGFuIGEtcHJpb3JpIG1ldGhvZCBwcm90b2NvbCBkb2N1bWVudD9gID0gIkNFRVNBVDJfMi4xIiwNCiAgICAgICAgICAgYDMuMS4gSXMgdGhlIGFwcHJvYWNoIHRvIHNlYXJjaGluZyBjbGVhcmx5IGRlZmluZWQgc3lzdGVtYXRpYyBhbmRcbnRyYW5zcGFyZW50P2AgPSAiQ0VFU0FUMl8zLjEiLA0KICAgICAgICAgICBgMy4yLiBJcyB0aGUgc2VhcmNoIGNvbXByZWhlbnNpdmU/YCA9ICJDRUVTQVQyXzMuMiIsDQogICAgICAgICAgIGA0LjEuIEFyZSBlbGlnaWJpbGl0eSBjcml0ZXJpYSBjbGVhcmx5IGRlZmluZWQ/YCA9ICJDRUVTQVQyXzQuMSIsDQogICAgICAgICAgIGA0LjIuIEFyZSBlbGlnaWJpbGl0eSBjcml0ZXJpYSBjb25zaXN0ZW50bHkgYXBwbGllZCB0byBhbGwgcG90ZW50aWFsbHkgcmVsZXZhbnRcbmFydGljbGVzIGFuZCBzdHVkaWVzIGZvdW5kIGR1cmluZyB0aGUgc2VhcmNoP2AgPSAiQ0VFU0FUMl80LjIiLA0KICAgICAgICAgICBgNC4zLiBBcmUgZWxpZ2liaWxpdHkgZGVjaXNpb25zIHRyYW5zcGFyZW50bHkgcmVwb3J0ZWQ/YCA9ICJDRUVTQVQyXzQuMyIsDQogICAgICAgICAgIGA1LjEuIERvZXMgdGhlIHJldmlldyBjcml0aWNhbGx5IGFwcHJhaXNlIGVhY2ggc3R1ZHk/YCA9ICJDRUVTQVQyXzUuMSIsDQogICAgICAgICAgIGA1LjIuIER1cmluZyBjcml0aWNhbCBhcHByYWlzYWwgd2FzIGFuIGVmZm9ydCBtYWRlIHRvIG1pbmltaXNlXG5zdWJqZWN0aXZpdHk/YCA9ICJDRUVTQVQyXzUuMiIsDQogICAgICAgICAgIGA2LjEuIElzIHRoZSBtZXRob2Qgb2YgZGF0YSBleHRyYWN0aW9uIGZ1bGx5IGRvY3VtZW50ZWQ/YCA9ICJDRUVTQVQyXzYuMSIsDQogICAgICAgICAgIGA2LjIuIEFyZSB0aGUgZXh0cmFjdGVkIGRhdGEgcmVwb3J0ZWQgZm9yIGVhY2ggc3R1ZHk/YCA9ICJDRUVTQVQyXzYuMiIsDQogICAgICAgICAgIGA2LjMuIFdlcmUgZXh0cmFjdGVkIGRhdGEgY3Jvc3MgY2hlY2tlZCBieSBtb3JlIHRoYW4gb25lIHJldmlld2VyP2AgPSAiQ0VFU0FUMl82LjMiLA0KICAgICAgICAgICBgNy4xLiBJcyB0aGUgY2hvaWNlIG9mIHN5bnRoZXNpcyBhcHByb2FjaCBhcHByb3ByaWF0ZT9gID0gIkNFRVNBVDJfNy4xIiwNCiAgICAgICAgICAgYDcuMi4gSXMgYSBzdGF0aXN0aWNhbCBlc3RpbWF0ZSBvZiBwb29sZWQgZWZmZWN0IHByb3ZpZGVkIHRvZ2V0aGVyIHdpdGhcbm1lYXN1cmUgb2YgdmFyaWFuY2UgYW5kIGhldGVyb2dlbmVpdHkgYW1vbmcgc3R1ZGllcz9gID0gIkNFRVNBVDJfNy4yIiwNCiAgICAgICAgICAgYDcuMyBJcyB2YXJpYWJpbGl0eSBpbiB0aGUgc3R1ZHkgZmluZGluZ3MgaW52ZXN0aWdhdGVkIGFuZCBkaXNjdXNzZWQ/YCA9ICJDRUVTQVQyXzcuMyIsDQogICAgICAgICAgIGA4LjEgSGF2ZSB0aGUgYXV0aG9ycyBjb25zaWRlcmVkIGxpbWl0YXRpb25zIGluIHRoZSBzeW50aGVzaXM/YCA9ICJDRUVTQVQyXzguMSIpLA0KICAgICAgICAgcXVlc3Rpb24gPSBmYWN0b3IocXVlc3Rpb24sIGxldmVscyA9IHJldihsZXZlbHMocXVlc3Rpb24pKSksDQogICAgICAgICBzY29yZSA9IGZhY3RvcihzY29yZSwgbGV2ZWxzID0gbGV2ZWxzKHNjb3JlKVtjKDQsMSwzLDIpXSkpDQoNCiMgQ3JlYXRlIENFRVNBVCBwbG90IA0KZmlnMmEgPC0gZ2dwbG90KGRhdGEgPSBwZXJjZW50X2NlZXNhdF9zY29yZSwgYWVzKHggPSBxdWVzdGlvbiwgeSA9IHBlcmNlbnQsIGZpbGwgPSBzY29yZSkpICsNCiAgZ2VvbV9jb2wod2lkdGggPSAwLjcsIHBvc2l0aW9uID0gImZpbGwiLCBjb2xvciA9ICJibGFjayIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IG4pLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2ZpbGwodmp1c3QgPSAwLjUpLCBzaXplID0gNywgZm9udGZhY2UgPSAiYm9sZCIpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQocmV2ZXJzZSA9IFRSVUUpKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNGRjAwMDAiLCIjRkZENzAwIiwiIzAwODAwMCIsICIjREFBNTIwIiksIG5hbWUgPSAiU2NvcmU6IikgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArDQogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksIA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCANCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwNCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwNCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyNSksDQogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjUpLCANCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsICANCiAgICAgICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSAibGVmdCIsICANCiAgICAgICAgbGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiwNCiAgICAgICAgbGVnZW5kLmJveCA9ICJob3Jpem9udGFsIiwgIA0KICAgICAgICBsZWdlbmQuYm94Lmp1c3QgPSAibGVmdCIsICANCiAgICAgICAgbGVnZW5kLnRpdGxlLmFsaWduID0gMC41LCAgDQogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMSwgImNtIiksICANCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPTI1KSwNCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDI1KSwgIA0KICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCksDQogICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksIA0KICAgICAgICBwbG90LnRhZyA9IGVsZW1lbnRfdGV4dChzaXplID0gMjUpKSArIA0KICB5bGFiKCJQZXJjZW50YWdlIikgKyANCiAgeGxhYigiQ0VFU0FUIFF1ZXN0aW9uIikgKyAgDQogIGxhYnModGFnID0gIkEiKQ0KDQpmaWcyYQ0KDQp0b3RhbF9uIDwtIHN1bShwZXJjZW50X2NlZXNhdF9zY29yZSRuKQ0KcGVyY2VudGFnZXMgPC0gdGliYmxlKA0KICByZWRfcGVyY2VudGFnZSA9IHN1bShwZXJjZW50X2NlZXNhdF9zY29yZSRuW3BlcmNlbnRfY2Vlc2F0X3Njb3JlJHNjb3JlID09ICJSZWQiXSkgLyB0b3RhbF9uICogMTAwLA0KICBhbWJlcl9wZXJjZW50YWdlID0gc3VtKHBlcmNlbnRfY2Vlc2F0X3Njb3JlJG5bcGVyY2VudF9jZWVzYXRfc2NvcmUkc2NvcmUgPT0gIkFtYmVyIl0pIC8gdG90YWxfbiAqIDEwMCwNCiAgZ3JlZW5fcGVyY2VudGFnZSA9IHN1bShwZXJjZW50X2NlZXNhdF9zY29yZSRuW3BlcmNlbnRfY2Vlc2F0X3Njb3JlJHNjb3JlID09ICJHcmVlbiJdKSAvIHRvdGFsX24gKiAxMDAsDQogIGdvbGRfcGVyY2VudGFnZSA9IHN1bShwZXJjZW50X2NlZXNhdF9zY29yZSRuW3BlcmNlbnRfY2Vlc2F0X3Njb3JlJHNjb3JlID09ICJHb2xkIl0pIC8gdG90YWxfbiAqIDEwMA0KKQ0KDQogcGVyY2VudGFnZXMNCg0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJmaWcyYS5wZGYiKSwgd2lkdGggPSAyNSwgaGVpZ2h0ID0gMTUsIHVuaXRzID0gImNtIiwgc2NhbGUgPSAyLCBkcGkgPSA4MDApDQojIGdnc2F2ZShoZXJlKCJmaWd1cmVzIiwgImZpZzJhLmpwZyIpLCB3aWR0aCA9IDI1LCBoZWlnaHQgPSAxNSwgdW5pdHMgPSAiY20iLCBzY2FsZSA9IDIsIGRwaSA9IDgwMCkNCmBgYA0KDQojIyANCk1ha2luZyB0aGUgQ0VFU0FUIHF1ZXN0aW9uIGdyb3VwcyBmb3IgcmVzdWx0IHJlcG9ydGluZw0KYGBge3J9DQojIENyZWF0ZSBuZXcgY2F0ZWdvcmllcyBmb3Igc3BlY2lmaWVkIHF1ZXN0aW9ucyBpbiBudW1lcmljYWwgb3JkZXINCnBlcmNlbnRfY2Vlc2F0X3Njb3JlJGNvbWJpbmVkX2NhdGVnb3J5IDwtIGlmZWxzZSgNCiAgZ3JlcGwoIl4xXFwuMSIsIHBlcmNlbnRfY2Vlc2F0X3Njb3JlJHF1ZXN0aW9uKSB8IGdyZXBsKCJeMlxcLjEiLCBwZXJjZW50X2NlZXNhdF9zY29yZSRxdWVzdGlvbiksDQogICJTdHVkeSBRdWVzdGlvbiIsDQogIGlmZWxzZShncmVwbCgiXjNcXC4xIiwgcGVyY2VudF9jZWVzYXRfc2NvcmUkcXVlc3Rpb24pIHwgZ3JlcGwoIl4zXFwuMiIsIHBlcmNlbnRfY2Vlc2F0X3Njb3JlJHF1ZXN0aW9uKSwNCiAgICAiTGl0ZXJhdHVyZSBTZWFyY2hpbmciLA0KICAgIGlmZWxzZShncmVwbCgiXjRcXC4xIiwgcGVyY2VudF9jZWVzYXRfc2NvcmUkcXVlc3Rpb24pIHwgZ3JlcGwoIl40XFwuMiIsIHBlcmNlbnRfY2Vlc2F0X3Njb3JlJHF1ZXN0aW9uKSB8IGdyZXBsKCJeNFxcLjMiLCBwZXJjZW50X2NlZXNhdF9zY29yZSRxdWVzdGlvbiksDQogICAgICAiTGl0ZXJhdHVyZSBTY3JlZW5pbmciLA0KICAgICAgaWZlbHNlKGdyZXBsKCJeNVxcLjEiLCBwZXJjZW50X2NlZXNhdF9zY29yZSRxdWVzdGlvbikgfCBncmVwbCgiXjVcXC4yIiwgcGVyY2VudF9jZWVzYXRfc2NvcmUkcXVlc3Rpb24pIHwgDQogICAgICAgICAgICAgZ3JlcGwoIl42XFwuMSIsIHBlcmNlbnRfY2Vlc2F0X3Njb3JlJHF1ZXN0aW9uKSB8IGdyZXBsKCJeNlxcLjIiLCBwZXJjZW50X2NlZXNhdF9zY29yZSRxdWVzdGlvbikgfCBncmVwbCgiXjZcXC4zIiwgcGVyY2VudF9jZWVzYXRfc2NvcmUkcXVlc3Rpb24pLA0KICAgICAgICAiRGF0YSBFeHRyYWN0aW9uIiwgDQogICAgICAgIGlmZWxzZShncmVwbCgiXjciLCBwZXJjZW50X2NlZXNhdF9zY29yZSRxdWVzdGlvbiksICJEYXRhIEFuYWx5c2lzIiwgDQogICAgICAgICAgaWZlbHNlKGdyZXBsKCJeOCIsIHBlcmNlbnRfY2Vlc2F0X3Njb3JlJHF1ZXN0aW9uKSwgIlN0dWR5IExpbWl0YXRpb25zIiwgIk90aGVyIikpKSkpKQ0KDQojIEdyb3VwIGJ5IGNvbWJpbmVkX2NhdGVnb3J5IGFuZCBzY29yZSwgdGhlbiBzdW1tYXJpemUNCnBlcmNlbnRfY2Vlc2F0X3Njb3JlX2dyb3VwZWQgPC0gcGVyY2VudF9jZWVzYXRfc2NvcmUgJT4lDQogIGdyb3VwX2J5KGNvbWJpbmVkX2NhdGVnb3J5LCBzY29yZSkgJT4lDQogIHN1bW1hcmlzZSh0b3RhbF9uID0gc3VtKG4pKQ0KDQojIENhbGN1bGF0ZSB0aGUgdG90YWwgY291bnQgZm9yIGVhY2ggc3BlY2lhbCBjYXRlZ29yeQ0KdG90YWxfY291bnRzIDwtIHBlcmNlbnRfY2Vlc2F0X3Njb3JlX2dyb3VwZWQgJT4lDQogIGdyb3VwX2J5KGNvbWJpbmVkX2NhdGVnb3J5KSAlPiUNCiAgc3VtbWFyaXNlKHRvdGFsX2NvdW50ID0gc3VtKHRvdGFsX24pKQ0KDQojIEpvaW4gdG90YWwgY291bnRzIHdpdGggZ3JvdXBlZCBkYXRhDQpwZXJjZW50X2NlZXNhdF9zY29yZV9ncm91cGVkIDwtIGxlZnRfam9pbihwZXJjZW50X2NlZXNhdF9zY29yZV9ncm91cGVkLCB0b3RhbF9jb3VudHMsIGJ5ID0gImNvbWJpbmVkX2NhdGVnb3J5IikNCg0KIyBBZGQgYSBjb2x1bW4gZm9yIHJlbGF0aXZlIHBlcmNlbnQNCnBlcmNlbnRfY2Vlc2F0X3Njb3JlX2dyb3VwZWQgPC0gcGVyY2VudF9jZWVzYXRfc2NvcmVfZ3JvdXBlZCAlPiUNCiAgbXV0YXRlKHJlbGF0aXZlX3BlcmNlbnQgPSAodG90YWxfbiAvIHRvdGFsX2NvdW50KSAqIDEwMCkNCg0KcHJpbnQocGVyY2VudF9jZWVzYXRfc2NvcmVfZ3JvdXBlZCkNCiMgdmlldyhwZXJjZW50X2NlZXNhdF9zY29yZV9ncm91cGVkKQ0KYGBgDQoNCiMjIA0KQ2FsY3VsYXRpbmcgYWx0bWV0cmljIGZvciBlYWNoIHN0dWR5IA0KYGBge3J9DQojIGxvYWQgZGF0YQ0KYmliX2FsdCA8LSByZWFkX2NzdihoZXJlKCJkYXRhIiwic2NvcHVzLmNzdiIpKSANCg0KIyBmdW5jdGlvbiBnZXRBbHRtZXRyaWNzKCksIHRoZSBvbmx5IHBhcmFtZXRlciBpcyBkb2k7IHNlZSBleGFtcGxlIGJlbG93DQpnZXRBbHRtZXRyaWNzIDwtIGZ1bmN0aW9uKGRvaSA9IE5VTEwsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGZvcHRpb25zID0gbGlzdCgpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uKSB7DQogICAgaWYgKCFpcy5udWxsKGRvaSkpIGRvaSA8LSBzdHJpbmdyOjpzdHJfYygiZG9pLyIsIGRvaSkNCiAgICBpZGVudGlmaWVycyA8LSBwdXJycjo6Y29tcGFjdChsaXN0KGRvaSkpDQogICAgaWYgKCFpcy5udWxsKGlkZW50aWZpZXJzKSkgew0KICAgICAgaWRzIDwtIGlkZW50aWZpZXJzW1sxXV0NCiAgICB9DQogICAgYmFzZV91cmwgPC0gImh0dHA6Ly9hcGkuYWx0bWV0cmljLmNvbS92MS8iDQogICAgI3JlcXVlc3QgPC0gaHR0cjo6R0VUKHBhc3RlMChiYXNlX3VybCwgaWRzKSwgaHR0cjo6YWRkX2hlYWRlcnMoInVzZXItYWdlbnQiID0gIiNyc3RhdHMgckFsdG1lcnRpYyBwYWNrYWdlIGh0dHBzOi8vZ2l0aHViLmNvbS9yb3BlbnNjaS9yQWx0bWV0cmljIikpDQogICAgcmVxdWVzdCA8LSBodHRyOjpHRVQocGFzdGUwKGJhc2VfdXJsLCBpZHMpKQ0KICAgIHJlc3VsdHMgPC0NCiAgICAgIGpzb25saXRlOjpmcm9tSlNPTihodHRyOjpjb250ZW50KHJlcXVlc3QsIGFzID0gInRleHQiKSwgZmxhdHRlbiA9IFRSVUUpDQogICAgcmVzdWx0cyA8LSBybGlzdDo6bGlzdC5mbGF0dGVuKHJlc3VsdHMpDQogICAgY2xhc3MocmVzdWx0cykgPC0gImFsdG1ldHJpYyINCiAgICByZXN1bHRzDQp9DQphbHRtZXRyaWMuY3Jhd2xlciA8LSBsaXN0KE5VTEwpDQpmb3IgKG4gaW4gMTpsZW5ndGgoYmliX2FsdCRET0kpKSB7DQogIyBmb3JtYXQgYWx0bWV0cmljIG9iamVjdA0KICBmb3JtYXQuQWx0bWV0cmljIDwtIGZ1bmN0aW9uKGFsdG1ldHJpYy5vYmplY3QpIHsNCiAgc3RhdHMgPC0gYWx0bWV0cmljLm9iamVjdFtncmVwKCJeY2l0ZWQiLCBuYW1lcyhhbHRtZXRyaWMub2JqZWN0KSldDQogIHN0YXRzIDwtIGRhdGEuZnJhbWUoc3RhdHMsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkNCiAgZGF0YS5mcmFtZShwYXBlcl90aXRsZSA9IGFsdG1ldHJpYy5vYmplY3QkdGl0bGUsDQogICAgICAgICAgICAgam91cm5hbCA9IGFsdG1ldHJpYy5vYmplY3Qkam91cm5hbCwNCiAgICAgICAgICAgICBkb2kgPSBhbHRtZXRyaWMub2JqZWN0JGRvaSwNCiAgICAgICAgICAgICAjc3ViamVjdCA9IGFsdG1ldHJpYy5vYmplY3Qkc3ViamVjdHMsDQogICAgICAgICAgICAgQWx0bWV0cmljLnNjb3JlID0gYWx0bWV0cmljLm9iamVjdCRzY29yZSwNCiAgICAgICAgICAgICBzdGF0cyA9IHN0YXRzKQ0KfQ0KICAgIyBKQVNPTiBmb3JtYXRlDQogIGFsdG1ldHJpYy5jcmF3bGVyW1tuXV0gIDwtICB0cnkobGlzdChmb3JtYXQuQWx0bWV0cmljKGdldEFsdG1ldHJpY3MoZG9pID0gYmliX2FsdCRET0lbbl0pKSkpICMgaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMTQwNTk2NTcvaG93LXRvLXNraXAtYW4tZXJyb3ItaW4tYS1sb29wP3JxPTENCiAgDQogICMgY3JlYXRlIGEgZGF0YWZyYW1lIGZ1bmN0aW9uDQogIGFsdG1ldHJpY19kZiA8LSBmdW5jdGlvbihhbHRtZXRyaWMub2JqZWN0KSB7DQogIGRmIDwtIGRhdGEuZnJhbWUodCh1bmxpc3QoYWx0bWV0cmljLm9iamVjdCkpLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQogIH0NCiAgI2FsdG1ldHJpYy5jcmF3bGVyW1tuXV0gIDwtICB0cnkobGlzdChhbHRtZXRyaWNfZGYoZ2V0QWx0bWV0cmljcyhkb2kgPSBET0lzW25dKSkpKQ0KICAjIGNyZWF0ZSBhIGZ1bmN0aW9uIHRvIHN1bW1hcml6ZSBBbHRtZXRyaWMgb2JqZWN0DQogIHN1bW1hcnkuYWx0bWV0cmljIDwtIGZ1bmN0aW9uKHgsIC4uLikgew0KICBpZiAoaW5oZXJpdHMoeCwgImFsdG1ldHJpYyIpKSAgew0Kc3RyaW5nIDwtICJBbHRtZXRyaWNzIG9uOiBcIiVzXCIgd2l0aCBhbHRtZXRyaWNfaWQ6ICVzIHB1Ymxpc2hlZCBpbiAlcy4iDQp2YWxzICAgPC0gYyh4JHRpdGxlLCAgeCRhbHRtZXRyaWNfaWQsIHgkam91cm5hbCkNCiBpZigiam91cm5hbCIgJWluJSBuYW1lcyh4KSkgew0KICBjYXQoZG8uY2FsbChzcHJpbnRmLCBhcy5saXN0KGMoc3RyaW5nLCB2YWxzKSkpKQ0KIH0gZWxzZSB7DQogICBzdHJpbmcgPC0gIkFsdG1ldHJpY3Mgb246IFwiJXNcIiB3aXRoIGFsdG1ldHJpY19pZDogJXMiDQogICBjYXQoZG8uY2FsbChzcHJpbnRmLCBhcy5saXN0KGMoc3RyaW5nLCB2YWxzKSkpKQ0KIH0NCiAgY2F0KCJcbiIpDQogIHN0YXRzIDwtIHhbZ3JlcCgiXmNpdGVkIiwgbmFtZXMoeCkpXQ0KICBzdGF0cyA8LSBkYXRhLmZyYW1lKHN0YXRzLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQogIHByaW50KGRhdGEuZnJhbWUoc3RhdHMgPSB0KHN0YXRzKSkpDQogIH0NCn0NCiAgIyBjcmF3bA0KICMgYWx0bWV0cmljLmNyYXdsZXJbW25dXSA8LSB0cnkobGlzdChzdW1tYXJ5LmFsdG1ldHJpYyhnZXRBbHRtZXRyaWNzKGRvaSA9IERPSXNbbl0pKSkpDQp9DQojIHNhdmUgcmVzdWx0cyBmcm9tIGFsdG1ldHJpYy5jcmF3bGVyIGFuZCByZXRyaWV2ZSBsaXN0cyB3aXRoaW4gbGlzdHMNCmFsdG1ldHJpYy5jcmF3bGVyMiA8LSBzYXBwbHkoYWx0bWV0cmljLmNyYXdsZXIsIGZ1bmN0aW9uKHgpIHt4fSkNCiMgcmV0cmlldmUgc3RhdHMNCmFsdG1ldHJpYy5zdW1tYXJ5IDwtIGRhdGEuZnJhbWUocGFwZXJfdGl0bGUgPSBzYXBwbHkoYWx0bWV0cmljLmNyYXdsZXIyLCBmdW5jdGlvbih4KSAgaWZlbHNlKGNsYXNzKHgpID09ICJkYXRhLmZyYW1lIix4JHBhcGVyX3RpdGxlLE5BKSksDQogICAgICAgICAgIGpvdXJuYWwgPSBzYXBwbHkoYWx0bWV0cmljLmNyYXdsZXIyLCBmdW5jdGlvbih4KSBpZmVsc2UoY2xhc3MoeCkgPT0gImRhdGEuZnJhbWUiLHgkam91cm5hbCxOQSkpLA0KICAgICAgICAgICBkb2kgPSBzYXBwbHkoYWx0bWV0cmljLmNyYXdsZXIyLCBmdW5jdGlvbih4KSBpZmVsc2UoY2xhc3MoeCkgPT0gImRhdGEuZnJhbWUiLHgkZG9pLE5BKSksDQogICAgICAgICAgICNzdWJqZWN0ID0gc2FwcGx5KGFsdG1ldHJpYy5jcmF3bGVyMiwgZnVuY3Rpb24oeCkgaWZlbHNlKGNsYXNzKHgpID09ICJkYXRhLmZyYW1lIix4JHN1YmplY3QsTkEpKSwNCiAgICAgICAgICAgQWx0bWV0cmljLnNjb3JlID0gc2FwcGx5KGFsdG1ldHJpYy5jcmF3bGVyMiwgZnVuY3Rpb24oeCkgaWZlbHNlKGNsYXNzKHgpID09ICJkYXRhLmZyYW1lIix4JEFsdG1ldHJpYy5zY29yZSwwKSksDQogICAgICAgICAgIHBvbGljeSA9IHNhcHBseShhbHRtZXRyaWMuY3Jhd2xlcjIsIGZ1bmN0aW9uKHgpIGlmZWxzZShjbGFzcyh4KSA9PSAiZGF0YS5mcmFtZSIsaWZlbHNlKCFpcy5udWxsKHgkc3RhdHMuY2l0ZWRfYnlfcG9saWNpZXNfY291bnQpLHgkc3RhdHMuY2l0ZWRfYnlfcG9saWNpZXNfY291bnQsMCksMCkpLA0KICAgICAgICAgICBwYXRlbnQgPSBzYXBwbHkoYWx0bWV0cmljLmNyYXdsZXIyLCBmdW5jdGlvbih4KSBpZmVsc2UoY2xhc3MoeCkgPT0gImRhdGEuZnJhbWUiLGlmZWxzZSghaXMubnVsbCh4JHN0YXRzLmNpdGVkX2J5X3BhdGVudHNfY291bnQpLHgkc3RhdHMuY2l0ZWRfYnlfcGF0ZW50c19jb3VudCwwKSwwKSkNCiAgICAgICAgICAgKQ0KIyBBZGRpbmcgbmV3IGNvbHVtbnMgdG8gYmliX2FsdCBkYXRhZnJhbWUNCmJpYl9hbHQgPC0gYmliX2FsdCAlPiUNCiAgIG11dGF0ZShBbHRtZXRyaWMuc2NvcmUgPSBhbHRtZXRyaWMuc3VtbWFyeSRBbHRtZXRyaWMuc2NvcmUsIA0KICAgICAgICAgIHBvbGljeSA9IGFsdG1ldHJpYy5zdW1tYXJ5JHBvbGljeSwgDQogICAgICAgICAgcGF0ZW50ID0gYWx0bWV0cmljLnN1bW1hcnkkcGF0ZW50KQ0KDQojIERlZmluaW5nIHRoZSBzY29yaW5nIGZ1bmN0aW9uDQpzY29yZSA8LSBmdW5jdGlvbih4KSB7DQogIGNhc2Vfd2hlbigNCiAgICB4ID09ICdSZWQnIH4gMCwNCiAgICB4ID09ICdBbWJlcicgfiAxLA0KICAgIHggPT0gJ0dyZWVuJyB+IDMsDQogICAgeCA9PSAnR29sZCcgfiA0LA0KICAgIFRSVUUgfiBOQV9yZWFsXw0KICApDQp9DQojIEFwcGx5IHRoZSBzY29yaW5nIGZ1bmN0aW9uIGFjcm9zcyBhbGwgY29sdW1ucyBzdGFydGluZyB3aXRoICJDRUVTQVQiDQpzZCA8LSBzZCAlPiUNCiAgbXV0YXRlKGFjcm9zcyhzdGFydHNfd2l0aCgiQ0VFU0FUIiksIHNjb3JlLCAubmFtZXMgPSAicG9pbnRzX3suY29sfSIpKQ0KIyBTdW0gYWxsIHRoZSBwb2ludHMgY29sdW1ucyB0byBjcmVhdGUgYSAndG90YWxfcG9pbnRzJyBjb2x1bW4NCnNkIDwtIHNkICU+JQ0KICBtdXRhdGUodG90YWxfcG9pbnRzID0gcm93U3VtcyhzZWxlY3QoLiwgc3RhcnRzX3dpdGgoInBvaW50c18iKSksIG5hLnJtID0gVFJVRSkpDQoNCmBgYA0KDQojIyBGaWd1cmUgMmINCkNFRVNBVCBzY29yZXMgZm9yIG1ldGEtYW5hbHlzZXMgY2l0ZWQgaW4gcG9saWN5IGRvY3VtZW50cyAobGVmdCBwYW5lbCkgYW5kIHRob3NlIG5vdCBjaXRlZCBpbiBwb2xpY3kgZG9jdW1lbnRzIChyaWdodCBwYW5lbCkuIA0KYGBge3IsIGZpZy53aWR0aD0yNSwgZmlnLmhlaWdodD0xNX0NCg0KIyBDb252ZXJ0aW5nIHBvbGljeSB0byBiaW5hcnkgYW5kIGRyb3BwaW5nIE5Bcw0Kc2RfYmliX2FsdF9wb2xpY3kgPC0gbGVmdF9qb2luKHNkLCBwb2wsIGpvaW5fYnkoImF1dGhvcl95ZWFyIiksIG11bHRpcGxlID0gImFsbCIpDQoNCnNkX2JpYl9hbHRfcG9saWN5IDwtIHNkX2JpYl9hbHRfcG9saWN5ICU+JQ0KICAjIEVuc3VyZSBvbmx5IHVuaXF1ZSBhdXRob3JfeWVhciBlbnRyaWVzIGFyZSBrZXB0DQogIGRpc3RpbmN0KGF1dGhvcl95ZWFyLCAua2VlcF9hbGwgPSBUUlVFKSAlPiUNCiAgDQogICMgQ3JlYXRlIGEgbmV3IGNvbHVtbiBjYXRlZ29yaXppbmcgcG9saWN5IHByZXNlbmNlDQogIG11dGF0ZSgNCiAgICBwb2xpY3lfc3RhdHVzID0gY2FzZV93aGVuKA0KICAgICAgaXMubmEocG9saWN5X3RpdGxlKSB+ICJObyBQb2xpY3kiLCAgICMgSWYgbWlzc2luZyAoTkEpLCBjbGFzc2lmeSBhcyAiTm8gUG9saWN5Ig0KICAgICAgcG9saWN5X3RpdGxlID09ICJubyBwb2xpY3kiIH4gIk5vIFBvbGljeSIsICAjIElmIGV4cGxpY2l0bHkgIm5vIHBvbGljeSIsIGNsYXNzaWZ5IGFzICJObyBQb2xpY3kiDQogICAgICBUUlVFIH4gIlBvbGljeSIgICAjIEV2ZXJ5dGhpbmcgZWxzZSBpcyBjb25zaWRlcmVkIGEgcG9saWN5IGRvY3VtZW50DQogICAgKQ0KICApDQoNCnBlcmNlbnRfY2Vlc2F0X3Njb3JlMSA8LSBzZF9iaWJfYWx0X3BvbGljeSAlPiUNCiAgZmlsdGVyKCFpcy5uYShhdXRob3JfeWVhcikpICU+JQ0KICBzZWxlY3Qoc3R1ZGllcyA9IGF1dGhvcl95ZWFyLCBwb2xpY3lfc3RhdHVzLCBzdGFydHNfd2l0aCgiQ0VFIikpICU+JQ0KICBuYS5vbWl0KCkgJT4lDQogIHBpdm90X2xvbmdlcihjb2xzID0gLWMoc3R1ZGllcywgcG9saWN5X3N0YXR1cyksIG5hbWVzX3RvID0gInF1ZXN0aW9uIiwgdmFsdWVzX3RvID0gInNjb3JlIikgJT4lDQogIGdyb3VwX2J5KHBvbGljeV9zdGF0dXMsIHF1ZXN0aW9uLCBzY29yZSkgJT4lDQogIHN1bW1hcmlzZShuID0gbigpLCAuZ3JvdXBzID0gJ2Ryb3AnKSAlPiUNCiAgbXV0YXRlKHBlcmNlbnQgPSAobi9zdW0obikpKjEwMCwgDQogICAgICAgICBhY3Jvc3MoYyhxdWVzdGlvbiwgc2NvcmUpLCBhcy5mYWN0b3IpLA0KICAgICAgICAgcXVlc3Rpb24gPSBmY3RfcmVjb2RlKHF1ZXN0aW9uLCANCiAgICAgICAgICAgYDEuMWAgPSAiQ0VFU0FUMl8xLjEiLA0KICAgICAgICAgICBgMi4xYCA9ICJDRUVTQVQyXzIuMSIsDQogICAgICAgICAgIGAzLjFgID0gIkNFRVNBVDJfMy4xIiwNCiAgICAgICAgICAgYDMuMmAgPSAiQ0VFU0FUMl8zLjIiLA0KICAgICAgICAgICBgNC4xYCA9ICJDRUVTQVQyXzQuMSIsDQogICAgICAgICAgIGA0LjJgID0gIkNFRVNBVDJfNC4yIiwNCiAgICAgICAgICAgYDQuM2AgPSAiQ0VFU0FUMl80LjMiLA0KICAgICAgICAgICBgNS4xYCA9ICJDRUVTQVQyXzUuMSIsDQogICAgICAgICAgIGA1LjJgID0gIkNFRVNBVDJfNS4yIiwNCiAgICAgICAgICAgYDYuMWAgPSAiQ0VFU0FUMl82LjEiLA0KICAgICAgICAgICBgNi4yYCA9ICJDRUVTQVQyXzYuMiIsDQogICAgICAgICAgIGA2LjNgID0gIkNFRVNBVDJfNi4zIiwNCiAgICAgICAgICAgYDcuMWAgPSAiQ0VFU0FUMl83LjEiLA0KICAgICAgICAgICBgNy4yYCA9ICJDRUVTQVQyXzcuMiIsDQogICAgICAgICAgIGA3LjNgID0gIkNFRVNBVDJfNy4zIiwNCiAgICAgICAgICAgYDguMWAgPSAiQ0VFU0FUMl84LjEiKSwNCiAgICAgICAgIHF1ZXN0aW9uID0gZmFjdG9yKHF1ZXN0aW9uLCBsZXZlbHMgPSByZXYobGV2ZWxzKHF1ZXN0aW9uKSkpLA0KICAgICAgICAgc2NvcmUgPSBmYWN0b3Ioc2NvcmUsIGxldmVscyA9IGxldmVscyhzY29yZSlbYyg0LDEsMywyKV0pKQ0KDQoNCmZpZzJiIDwtIGdncGxvdChkYXRhID0gcGVyY2VudF9jZWVzYXRfc2NvcmUxLCBhZXMoeCA9IHF1ZXN0aW9uLCB5ID0gcGVyY2VudCwgZmlsbCA9IHNjb3JlKSkgKw0KICBnZW9tX2NvbCh3aWR0aCA9IDAuNywgcG9zaXRpb24gPSAiZmlsbCIsIGNvbG9yID0gImJsYWNrIikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gbiksIHBvc2l0aW9uID0gcG9zaXRpb25fZmlsbCh2anVzdCA9IDAuNSksIHNpemUgPSA3LCBmb250ZmFjZSA9ICJib2xkIikgKw0KICBjb29yZF9mbGlwKCkgKw0KICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZChyZXZlcnNlID0gVFJVRSkpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI0ZGMDAwMCIsIiNGRkQ3MDAiLCIjMDA4MDAwIiwgIiNEQUE1MjAiKSwgbmFtZSA9ICJTY29yZToiKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsNCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgDQogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksIA0KICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLA0KICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLA0KICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDI1KSwNCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyNSksIA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwNCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgDQogICAgICAgIHBsb3QudGFnID0gZWxlbWVudF90ZXh0KHNpemUgPSAyNSkpICsgDQogIHlsYWIoIlBlcmNlbnRhZ2UiKSArIA0KICB4bGFiKCJDRUVTQVQgUXVlc3Rpb24iKSArDQogIGZhY2V0X3dyYXAofnBvbGljeV9zdGF0dXMpICsNCiAgbGFicyh0YWcgPSAiQiIpDQoNCmZpZzJiDQojIGdnc2F2ZShoZXJlKCJmaWd1cmVzIiwgImZpZzJiLnBkZiIpLCB3aWR0aCA9IDI1LCBoZWlnaHQgPSAxNSwgdW5pdHMgPSAiY20iLCBzY2FsZSA9IDIsIGRwaSA9IDgwMCkNCiMgZ2dzYXZlKGhlcmUoImZpZ3VyZXMiLCAiZmlnMmIuanBnIiksIHdpZHRoID0gMjUsIGhlaWdodCA9IDE1LCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KDQoNCnBvbGljeSA8LSBzZF9iaWJfYWx0X3BvbGljeSR0b3RhbF9wb2ludHNbc2RfYmliX2FsdF9wb2xpY3kkcG9saWN5X3N0YXR1cyA9PSAiUG9saWN5Il0NCm5vdF9wb2xpY3kgPC0gc2RfYmliX2FsdF9wb2xpY3kkdG90YWxfcG9pbnRzW3NkX2JpYl9hbHRfcG9saWN5JHBvbGljeV9zdGF0dXMgPT0gIk5vIFBvbGljeSJdDQoNCg0KIyBDcmVhdGUgYSB0aWJibGUgZm9yIHBvbGljeSB2YWx1ZXMNCnBvbGljeV9kZiA8LSB0aWJibGUoDQogIHZhbHVlcyA9IHBvbGljeSwNCiAgY2F0ZWdvcnkgPSAiUG9saWN5Ig0KKQ0KDQojIENyZWF0ZSBhIHRpYmJsZSBmb3Igbm90X3BvbGljeSB2YWx1ZXMNCm5vdF9wb2xpY3lfZGYgPC0gdGliYmxlKA0KICB2YWx1ZXMgPSBub3RfcG9saWN5LA0KICBjYXRlZ29yeSA9ICJObyBQb2xpY3kiDQopDQoNCiMgQ29tYmluZSBib3RoIHRpYmJsZXMgaW50byBvbmUNCnBvbGljeV9jb21iaW5lZCA8LSBiaW5kX3Jvd3MocG9saWN5X2RmLCBub3RfcG9saWN5X2RmKQ0KDQojIFZpZXcgdGhlIGNvbWJpbmVkIHRpYmJsZQ0KcHJpbnQocG9saWN5X2NvbWJpbmVkKQ0KDQojIFFRIFBsb3QNCnFxbm9ybShwb2xpY3kpDQpxcWxpbmUocG9saWN5LCBjb2wgPSAicmVkIikNCg0KIyBRUSBQbG90DQpxcW5vcm0obm90X3BvbGljeSkNCnFxbGluZShub3RfcG9saWN5LCBjb2wgPSAicmVkIikgDQoNCg0KcG9saWN5X21vZGVsIDwtIGNsbShmYWN0b3IodmFsdWVzKSB+IGNhdGVnb3J5LCBkYXRhPXBvbGljeV9jb21iaW5lZCkNCg0Kc3VtbWFyeShwb2xpY3lfbW9kZWwpDQoNCnBvbGljeV9tb2RlbF9zZW5zaXRpdml0eSA8LSB0LnRlc3QocG9saWN5LG5vdF9wb2xpY3kpIA0KDQpwb2xpY3lfbW9kZWxfc2Vuc2l0aXZpdHkNCmBgYA0KDQojIyBGaWd1cmUgMmMNCkJhciBwbG90IHNob3dpbmcgdGhlIHBlcmNlbnRhZ2UgYW5kIHRvdGFsIGNvdW50IG9mIGJpYXMgbWV0aG9kb2xvZ2llcyB1c2VkIGluIG1ldGEtYW5hbHlzZXMgaW52ZXN0aWdhdGluZyB0aGUgaW1wYWN0cyBvZiBvcmdhbm9jaGxvcmluZSBwZXN0aWNpZGVzLiBOb3RlIHRoYXQgc29tZSBtZXRhLWFuYWx5c2VzIG1heSBjb250cmlidXRlIHRvIG11bHRpcGxlIHNlY3Rpb25zIGlmIHRoZSBzdHVkeSBpbnZvbHZlZCB0aGUgdXNlIG9mIG11bHRpcGxlIGJpYXMgYXNzZXNzbWVudCBtZXRob2RvbG9naWVzLiANCmBgYHtyLCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9MTB9DQojIENhbGN1bGF0ZSB0aGUgdG90YWwgY291bnQgZm9yIGVhY2ggY2F0ZWdvcnkNCmJpYXNfbWV0aG9kX2NvdW50IDwtIHNkICU+JSANCiAgc2VwYXJhdGVfcm93cyhiaWFzX2Fzc2Vzc21lbnRfbWV0aG9kLCBzZXAgPSAiLFxccysiKSAlPiUgDQogIGNvdW50KGJpYXNfYXNzZXNzbWVudF9tZXRob2QpICU+JQ0KICBmaWx0ZXIoYmlhc19hc3Nlc3NtZW50X21ldGhvZCAhPSAiTkEiKSAlPiUNCiAgZ3JvdXBfYnkoYmlhc19hc3Nlc3NtZW50X21ldGhvZCkgJT4lDQogIHN1bW1hcmlzZShuID0gc3VtKG4pKQ0KDQojIENhbGN1bGF0ZSBwcm9wb3J0aW9uIGFuZCBwZXJjZW50YWdlDQpiaWFzX21ldGhvZF9wY3QgPC0gYmlhc19tZXRob2RfY291bnQgJT4lDQogIG11dGF0ZShwcm9wb3J0aW9uID0gbiAvIDgzLA0KICAgICAgICAgcGVyY2VudGFnZSA9IHByb3BvcnRpb24gKiAxMDApDQoNCiMgQ3JlYXRlIHRoZSBiYXIgcGxvdA0KZmlnMmMgPC0gYmlhc19tZXRob2RfY291bnQgJT4lDQogIGdncGxvdChhZXMoeCA9IG4sIHkgPSByZW9yZGVyKGJpYXNfYXNzZXNzbWVudF9tZXRob2QsIG4pLCANCiAgICAgICAgICAgICBmaWxsID0gaWZlbHNlKGdyZXBsKCJOb3QgcmVwb3J0ZWQiLCBiaWFzX2Fzc2Vzc21lbnRfbWV0aG9kKSwgIiM3MzcwYjMiLCAiIzFiOWU3NyIpKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAwLjgsIGFscGhhID0gMC43KSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBpZmVsc2UobiA+IDEsIG4sICIiKSwgeCA9IG4gLyAyKSwgaGp1c3QgPSAwLjUsIHNpemUgPSAxMiwgY29sb3IgPSAiYmxhY2siKSArDQogIGdlb21fdGV4dChkYXRhID0gYmlhc19tZXRob2RfcGN0ICU+JSBmaWx0ZXIobiA+IDEpLCANCiAgICAgICAgICAgIGFlcyhsYWJlbCA9IHBhc3RlMCgiKCIsIHJvdW5kKHBlcmNlbnRhZ2UsIDEpLCAiJSkiKSwgeCA9IG4pLCANCiAgICAgICAgICAgIGhqdXN0ID0gLTAuMSwgc2l6ZSA9IDEyLCBjb2xvciA9ICJibGFjayIsIGZvbnRmYWNlID0gImJvbGQiKSArDQogIHNjYWxlX2ZpbGxfaWRlbnRpdHkoZ3VpZGUgPSAibm9uZSIpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwgMCksIGxpbWl0cyA9IGMoMCwgbWF4KGJpYXNfbWV0aG9kX2NvdW50JG4pICogMS4zKSkgKw0KICBsYWJzKHRpdGxlID0gIlB1YmxpY2F0aW9uIEJpYXMgQ291bnQiLCB4ID0gTlVMTCwgeSA9IE5VTEwsIHRhZyA9ICJDIiwgc2l6ZSA9IDMwKSArDQogIG9yZ2Fub2NobG9yVEhFTUUoKQ0KDQpmaWcyYw0KDQojIGdnc2F2ZShoZXJlKCJmaWd1cmVzIiwgImZpZzJjLnBkZiIpLCB3aWR0aCA9IDE2LCBoZWlnaHQgPSAxMCwgdW5pdHMgPSAiY20iLCBzY2FsZSA9IDIsIGRwaSA9IDgwMCkNCiMgZ2dzYXZlKGhlcmUoImZpZ3VyZXMiLCAiZmlnMmMuanBnIiksIHdpZHRoID0gMTYsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KYGBgDQoNCiMjIEZpZ3VyZSAyZA0KQmFyIHBsb3Qgc2hvd2luZyB0aGUgcGVyY2VudGFnZSBhbmQgdG90YWwgY291bnQgb2YgaGV0ZXJvZ2VuZWl0eSBhc3Nlc3NtZW50IG1ldGhvZHMgdXNlZCBpbiBtZXRhLWFuYWx5c2VzIGludmVzdGlnYXRpbmcgdGhlIGltcGFjdHMgb2Ygb3JnYW5vY2hsb3JpbmUgcGVzdGljaWRlcy4gTm90ZSB0aGF0IHNvbWUgbWV0YS1hbmFseXNlcyBtYXkgY29udHJpYnV0ZSB0byBtdWx0aXBsZSBzZWN0aW9ucyBpZiB0aGUgc3R1ZHkgaW52b2x2ZWQgbXVsdGlwbGUgaGV0ZXJvZ2VuZWl0eSBhc3Nlc3NtZW50cy4gUGVyY2VudGFnZSBpcyBzaG93aW5nIHRoZSBwcm9wb3J0aW9uIG9mIHN0dWRpZXMuDQpgYGB7ciwgZmlnLndpZHRoPTE2LCBmaWcuaGVpZ2h0PTEwfQ0KIyBGaWd1cmUgM2I6IEhldGVyb2dlbmVpdHkgQXNzZXNzbWVudCBNZXRob2RzDQpoZXRlcm9nZW5laXR5X2NvdW50IDwtIHNkICU+JSANCiAgc2VwYXJhdGVfcm93cyhoZXRlcm9nZW5laXR5X2Fzc2Vzc21lbnRfbWV0aG9kLCBzZXAgPSAiLFxccysiKSAlPiUgDQogIGNvdW50KGhldGVyb2dlbmVpdHlfYXNzZXNzbWVudF9tZXRob2QpICU+JQ0KICBmaWx0ZXIoaGV0ZXJvZ2VuZWl0eV9hc3Nlc3NtZW50X21ldGhvZCAhPSAiTkEiKSAlPiUNCiAgZ3JvdXBfYnkoaGV0ZXJvZ2VuZWl0eV9hc3Nlc3NtZW50X21ldGhvZCkgJT4lDQogIHN1bW1hcmlzZShuID0gc3VtKG4pKQ0KDQpoZXRlcm9nZW5laXR5X3BjdCA8LSBoZXRlcm9nZW5laXR5X2NvdW50ICU+JQ0KICBtdXRhdGUocHJvcG9ydGlvbiA9IG4gLyA4MywNCiAgICAgICAgIHBlcmNlbnRhZ2UgPSBwcm9wb3J0aW9uICogMTAwKQ0KDQpmaWcyZCA8LSBoZXRlcm9nZW5laXR5X2NvdW50ICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBuLCB5ID0gcmVvcmRlcihoZXRlcm9nZW5laXR5X2Fzc2Vzc21lbnRfbWV0aG9kLCBuKSwgDQogICAgICAgICAgICAgZmlsbCA9IGlmZWxzZShncmVwbCgiTm90IHJlcG9ydGVkIiwgaGV0ZXJvZ2VuZWl0eV9hc3Nlc3NtZW50X21ldGhvZCksICIjNzM3MGIzIiwgIiMxYjllNzciKSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMC44LCBhbHBoYSA9IDAuNykgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gaWZlbHNlKG4gPiAxLCBuLCAiIiksIHggPSBuIC8gMiksIGhqdXN0ID0gMC41LCBzaXplID0gMTIsIGNvbG9yID0gImJsYWNrIikgKw0KICBnZW9tX3RleHQoZGF0YSA9IGhldGVyb2dlbmVpdHlfcGN0ICU+JSBmaWx0ZXIobiA+IDEpLCANCiAgICAgICAgICAgIGFlcyhsYWJlbCA9IHBhc3RlMCgiKCIsIHJvdW5kKHBlcmNlbnRhZ2UsIDEpLCAiJSkiKSwgeCA9IG4pLCANCiAgICAgICAgICAgIGhqdXN0ID0gLTAuMSwgc2l6ZSA9IDEyLCBjb2xvciA9ICJibGFjayIsIGZvbnRmYWNlID0gImJvbGQiKSArDQogIHNjYWxlX2ZpbGxfaWRlbnRpdHkoZ3VpZGUgPSAibm9uZSIpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwgMCksIGxpbWl0cyA9IGMoMCwgbWF4KGhldGVyb2dlbmVpdHlfY291bnQkbikgKiAxLjMpKSArDQogIGxhYnModGl0bGUgPSAiSGV0ZXJvZ2VuZWl0eSBDb3VudCIsIHggPSBOVUxMLCB5ID0gTlVMTCwgdGFnID0gIkQiLCBzaXplID0gMzApICsNCiAgb3JnYW5vY2hsb3JUSEVNRSgpDQoNCmZpZzJkDQoNCiMgZ2dzYXZlKGhlcmUoImZpZ3VyZXMiLCAiZmlnMmQucGRmIiksIHdpZHRoID0gMTYsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJmaWcyZC5qcGciKSwgd2lkdGggPSAxNiwgaGVpZ2h0ID0gMTAsIHVuaXRzID0gImNtIiwgc2NhbGUgPSAyLCBkcGkgPSA4MDApDQoNCmBgYA0KIA0KIyMgRmlndXJlIDJlDQpCYXIgcGxvdCBzaG93aW5nIHRoZSBwZXJjZW50YWdlIGFuZCB0b3RhbCBjb3VudCBvZiBzZW5zaXRpdml0eSBhbmFseXNlcyBjb25kdWN0ZWQgaW4gbWV0YS1hbmFseXNlcyBpbnZlc3RpZ2F0aW5nIHRoZSBpbXBhY3RzIG9mIG9yZ2Fub2NobG9yaW5lIHBlc3RpY2lkZXMuIE5vdGUgdGhhdCBzb21lIG1ldGEtYW5hbHlzZXMgbWF5IGNvbnRyaWJ1dGUgdG8gbXVsdGlwbGUgc2VjdGlvbnMgaWYgdGhlIHN0dWR5IGludm9sdmVkIG11bHRpcGxlIHNlbnNpdGl2aXR5IGFuYWx5c2VzLg0KYGBge3IsIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD0xMH0NCiMgRmlndXJlIDNjOiBTZW5zaXRpdml0eSBBbmFseXNpcyBNZXRob2RzDQpzZW5zaXRpdml0eV9jb3VudCA8LSBzZCAlPiUgDQogIHNlcGFyYXRlX3Jvd3Moc2Vuc2l0aXZpdHlfYW5hbHlzaXNfbWV0aG9kLCBzZXAgPSAiLFxccysiKSAlPiUgDQogIGNvdW50KHNlbnNpdGl2aXR5X2FuYWx5c2lzX21ldGhvZCkgJT4lDQogIGZpbHRlcihzZW5zaXRpdml0eV9hbmFseXNpc19tZXRob2QgIT0gIk5BIikgJT4lDQogIGdyb3VwX2J5KHNlbnNpdGl2aXR5X2FuYWx5c2lzX21ldGhvZCkgJT4lDQogIHN1bW1hcmlzZShuID0gc3VtKG4pKQ0KDQpzZW5zaXRpdml0eV9wY3QgPC0gc2Vuc2l0aXZpdHlfY291bnQgJT4lDQogIG11dGF0ZShwcm9wb3J0aW9uID0gbiAvIDgzLA0KICAgICAgICAgcGVyY2VudGFnZSA9IHByb3BvcnRpb24gKiAxMDApDQoNCmZpZzJlIDwtIHNlbnNpdGl2aXR5X2NvdW50ICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBuLCB5ID0gcmVvcmRlcihzZW5zaXRpdml0eV9hbmFseXNpc19tZXRob2QsIG4pLCANCiAgICAgICAgICAgICBmaWxsID0gaWZlbHNlKGdyZXBsKCJOb3QgcmVwb3J0ZWQiLCBzZW5zaXRpdml0eV9hbmFseXNpc19tZXRob2QpLCAiIzczNzBiMyIsICIjMWI5ZTc3IikpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDAuOCwgYWxwaGEgPSAwLjcpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGlmZWxzZShuID4gMSwgbiwgIiIpLCB4ID0gbiAvIDIpLCBoanVzdCA9IDAuNSwgc2l6ZSA9IDEyLCBjb2xvciA9ICJibGFjayIpICsNCiAgZ2VvbV90ZXh0KGRhdGEgPSBzZW5zaXRpdml0eV9wY3QgJT4lIGZpbHRlcihuID4gMSksIA0KICAgICAgICAgICAgYWVzKGxhYmVsID0gcGFzdGUwKCIoIiwgcm91bmQocGVyY2VudGFnZSwgMSksICIlKSIpLCB4ID0gbiksIA0KICAgICAgICAgICAgaGp1c3QgPSAtMC4xLCBzaXplID0gMTIsIGNvbG9yID0gImJsYWNrIiwgZm9udGZhY2UgPSAiYm9sZCIpICsNCiAgc2NhbGVfZmlsbF9pZGVudGl0eShndWlkZSA9ICJub25lIikgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLCAwKSwgbGltaXRzID0gYygwLCBtYXgoc2Vuc2l0aXZpdHlfY291bnQkbikgKiAxLjMpKSArDQogIGxhYnModGl0bGUgPSAiU2Vuc2l0aXZpdHkgQW5hbHlzaXMgQ291bnQiLCB4ID0gTlVMTCwgeSA9IE5VTEwsIHRhZyA9ICJFIiwgc2l6ZSA9IDMwKSArDQogIG9yZ2Fub2NobG9yVEhFTUUoKQ0KDQpmaWcyZQ0KDQojIGdnc2F2ZShoZXJlKCJmaWd1cmVzIiwgImZpZzJlLnBkZiIpLCB3aWR0aCA9IDE2LCBoZWlnaHQgPSAxMCwgdW5pdHMgPSAiY20iLCBzY2FsZSA9IDIsIGRwaSA9IDgwMCkNCiMgZ2dzYXZlKGhlcmUoImZpZ3VyZXMiLCAiZmlnMmUuanBnIiksIHdpZHRoID0gMTYsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KDQpgYGANCg0KIyMgRmlndXJlIDJmDQpCYXIgcGxvdCBzaG93aW5nIHRoZSBwZXJjZW50YWdlIGFuZCB0b3RhbCBjb3VudCBvZiByZXBvcnRpbmcgZ3VpZGVsaW5lcyB1c2VkIGluIG1ldGEtYW5hbHlzZXMgaW52ZXN0aWdhdGluZyB0aGUgaW1wYWN0cyBvZiBvcmdhbm9jaGxvcmluZSBwZXN0aWNpZGVzLiBOb3RlIHRoYXQgc29tZSBtZXRhLWFuYWx5c2VzIG1heSBjb250cmlidXRlIHRvIG11bHRpcGxlIHNlY3Rpb25zIGlmIHRoZSBzdHVkeSBpbnZvbHZlZCB0aGUgdXNlIG9mIG11bHRpcGxlIHJlcG9ydGluZyBndWlkZWxpbmVzLg0KYGBge3IsIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD0xMH0NCiMgRmlndXJlIDNkOiBSZXBvcnRpbmcgR3VpZGVsaW5lcw0KcmVwb3J0aW5nX2d1aWRlX2NvdW50IDwtIHNkICU+JSANCiAgc2VwYXJhdGVfcm93cyhyZXBvcnRpbmdfc3RhbmRhcmRzX3R5cGUsIHNlcCA9ICIsXFxzKyIpICU+JSANCiAgY291bnQocmVwb3J0aW5nX3N0YW5kYXJkc190eXBlKSAlPiUNCiAgZmlsdGVyKHJlcG9ydGluZ19zdGFuZGFyZHNfdHlwZSAhPSAiTkEiKSAlPiUNCiAgbXV0YXRlKHJlcG9ydGluZ19zdGFuZGFyZHNfdHlwZSA9IGlmZWxzZShuIDwgMywgIk90aGVyIEd1aWRlbGluZXMiLCBhcy5jaGFyYWN0ZXIocmVwb3J0aW5nX3N0YW5kYXJkc190eXBlKSkpICU+JQ0KICBncm91cF9ieShyZXBvcnRpbmdfc3RhbmRhcmRzX3R5cGUpICU+JQ0KICBzdW1tYXJpc2UobiA9IHN1bShuKSkNCg0KcmVwb3J0aW5nX2d1aWRlX3BjdCA8LSByZXBvcnRpbmdfZ3VpZGVfY291bnQgJT4lDQogIG11dGF0ZShwcm9wb3J0aW9uID0gbiAvIDgzLA0KICAgICAgICAgcGVyY2VudGFnZSA9IHByb3BvcnRpb24gKiAxMDApDQoNCmZpZzJmIDwtIHJlcG9ydGluZ19ndWlkZV9jb3VudCAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gbiwgeSA9IHJlb3JkZXIocmVwb3J0aW5nX3N0YW5kYXJkc190eXBlLCBuKSwgDQogICAgICAgICAgICAgZmlsbCA9IGlmZWxzZShncmVwbCgiTm90IHJlcG9ydGVkIiwgcmVwb3J0aW5nX3N0YW5kYXJkc190eXBlKSwgIiM3MzcwYjMiLCAiIzFiOWU3NyIpKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAwLjgsIGFscGhhID0gMC43KSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBpZmVsc2UobiA+IDEsIG4sICIiKSwgeCA9IG4gLyAyKSwgaGp1c3QgPSAwLjUsIHNpemUgPSAxMiwgY29sb3IgPSAiYmxhY2siKSArDQogIGdlb21fdGV4dChkYXRhID0gcmVwb3J0aW5nX2d1aWRlX3BjdCAlPiUgZmlsdGVyKG4gPiAxKSwgDQogICAgICAgICAgICBhZXMobGFiZWwgPSBwYXN0ZTAoIigiLCByb3VuZChwZXJjZW50YWdlLCAwKSwgIiUpIiksIHggPSBuKSwgDQogICAgICAgICAgICBoanVzdCA9IC0wLjEsIHNpemUgPSAxMiwgY29sb3IgPSAiYmxhY2siLCBmb250ZmFjZSA9ICJib2xkIikgKw0KICBzY2FsZV9maWxsX2lkZW50aXR5KGd1aWRlID0gIm5vbmUiKSArDQogIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBjKDAsIDApLCBsaW1pdHMgPSBjKDAsIG1heChyZXBvcnRpbmdfZ3VpZGVfY291bnQkbikgKiAxLjMpKSArDQogIGxhYnModGl0bGUgPSAiUmVwb3J0aW5nIEd1aWRlbGluZSBDb3VudCIsIHggPSBOVUxMLCB5ID0gTlVMTCwgdGFnID0gIkYiLCBzaXplID0gMzApICsNCiAgDQogIG9yZ2Fub2NobG9yVEhFTUUoKQ0KDQpmaWcyZg0KDQojIGdnc2F2ZShoZXJlKCJmaWd1cmVzIiwgImZpZzJmLnBkZiIpLCB3aWR0aCA9IDE2LCBoZWlnaHQgPSAxMCwgdW5pdHMgPSAiY20iLCBzY2FsZSA9IDIsIGRwaSA9IDgwMCkNCiMgZ2dzYXZlKGhlcmUoImZpZ3VyZXMiLCAiZmlnMmYuanBnIiksIHdpZHRoID0gMTYsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KYGBgDQoNCiMjIENFRVNBVCByZXBvcml0bmcgZ3VpZGVsaW5lDQpDRUVTQVQgc2NvcmVzIGZvciBtZXRhLWFuYWx5c2VzIHJlZmVyZW5jaW5nIGEgcmVwb3J0aW5nIGd1aWRlbGluZSAocmlnaHQgcGFuZWwpIGFuZCB0aG9zZSBub3QgcmVmZXJlbmNpbmcgYSByZXBvcnRpbmcgZ3VpZGVsaW5lIChsZWZ0IHBhbmVsKS4NCmBgYHtyLCBmaWcud2lkdGg9MjUsIGZpZy5oZWlnaHQ9MTV9DQpzZF9iaWJfYWx0X2d1aWRlbGluZSA8LSBzZCAlPiUgDQogIG11dGF0ZShiaW5hcnlfZ3VpZGVsaW5lID0gaWZfZWxzZShyZXBvcnRpbmdfc3RhbmRhcmRzX3R5cGUgPT0gIk5vdCByZXBvcnRlZCIsICJOb3QgcmVwb3J0ZWQiLCAiUmVwb3J0ZWQiKSkgJT4lIA0KICAgIGRyb3BfbmEoYmluYXJ5X2d1aWRlbGluZSwgdG90YWxfcG9pbnRzKQ0KDQpwZXJjZW50X2NlZXNhdF9zY29yZTIgPC0gc2RfYmliX2FsdF9ndWlkZWxpbmUgJT4lDQogIGZpbHRlcighaXMubmEoYXV0aG9yX3llYXIpKSAlPiUNCiAgc2VsZWN0KHN0dWRpZXMgPSBhdXRob3JfeWVhciwgYmluYXJ5X2d1aWRlbGluZSwgc3RhcnRzX3dpdGgoIkNFRSIpKSAlPiUNCiAgbmEub21pdCgpICU+JQ0KICBwaXZvdF9sb25nZXIoY29scyA9IC1jKHN0dWRpZXMsIGJpbmFyeV9ndWlkZWxpbmUpLCBuYW1lc190byA9ICJxdWVzdGlvbiIsIHZhbHVlc190byA9ICJzY29yZSIpICU+JQ0KICBncm91cF9ieShiaW5hcnlfZ3VpZGVsaW5lLCBxdWVzdGlvbiwgc2NvcmUpICU+JQ0KICBzdW1tYXJpc2UobiA9IG4oKSwgLmdyb3VwcyA9ICdkcm9wJykgJT4lDQogIG11dGF0ZShwZXJjZW50ID0gKG4vc3VtKG4pKSoxMDAsIA0KICAgICAgICAgYWNyb3NzKGMocXVlc3Rpb24sIHNjb3JlKSwgYXMuZmFjdG9yKSwNCiAgICAgICAgIHF1ZXN0aW9uID0gZmN0X3JlY29kZShxdWVzdGlvbiwgDQogICAgICAgICAgIGAxLjFgID0gIkNFRVNBVDJfMS4xIiwNCiAgICAgICAgICAgYDIuMWAgPSAiQ0VFU0FUMl8yLjEiLA0KICAgICAgICAgICBgMy4xYCA9ICJDRUVTQVQyXzMuMSIsDQogICAgICAgICAgIGAzLjJgID0gIkNFRVNBVDJfMy4yIiwNCiAgICAgICAgICAgYDQuMWAgPSAiQ0VFU0FUMl80LjEiLA0KICAgICAgICAgICBgNC4yYCA9ICJDRUVTQVQyXzQuMiIsDQogICAgICAgICAgIGA0LjNgID0gIkNFRVNBVDJfNC4zIiwNCiAgICAgICAgICAgYDUuMWAgPSAiQ0VFU0FUMl81LjEiLA0KICAgICAgICAgICBgNS4yYCA9ICJDRUVTQVQyXzUuMiIsDQogICAgICAgICAgIGA2LjFgID0gIkNFRVNBVDJfNi4xIiwNCiAgICAgICAgICAgYDYuMmAgPSAiQ0VFU0FUMl82LjIiLA0KICAgICAgICAgICBgNi4zYCA9ICJDRUVTQVQyXzYuMyIsDQogICAgICAgICAgIGA3LjFgID0gIkNFRVNBVDJfNy4xIiwNCiAgICAgICAgICAgYDcuMmAgPSAiQ0VFU0FUMl83LjIiLA0KICAgICAgICAgICBgNy4zYCA9ICJDRUVTQVQyXzcuMyIsDQogICAgICAgICAgIGA4LjFgID0gIkNFRVNBVDJfOC4xIiksDQogICAgICAgICBxdWVzdGlvbiA9IGZhY3RvcihxdWVzdGlvbiwgbGV2ZWxzID0gcmV2KGxldmVscyhxdWVzdGlvbikpKSwNCiAgICAgICAgIHNjb3JlID0gZmFjdG9yKHNjb3JlLCBsZXZlbHMgPSBsZXZlbHMoc2NvcmUpW2MoNCwxLDMsMildKSkNCg0KY2Vlc2F0X3JlcG9ydCA8LSBnZ3Bsb3QoZGF0YSA9IHBlcmNlbnRfY2Vlc2F0X3Njb3JlMiwgYWVzKHggPSBxdWVzdGlvbiwgeSA9IHBlcmNlbnQsIGZpbGwgPSBzY29yZSkpICsNCiAgZ2VvbV9jb2wod2lkdGggPSAwLjcsIHBvc2l0aW9uID0gImZpbGwiLCBjb2xvciA9ICJibGFjayIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IG4pLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2ZpbGwodmp1c3QgPSAwLjUpLCBzaXplID0gNywgZm9udGZhY2UgPSAiYm9sZCIpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQocmV2ZXJzZSA9IFRSVUUpKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNGRjAwMDAiLCIjRkZENzAwIiwiIzAwODAwMCIsICIjREFBNTIwIiksIG5hbWUgPSAiU2NvcmU6IikgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArDQogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksIA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCANCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwNCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwNCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyNSksDQogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjUpLCANCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsICANCiAgICAgICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSAibGVmdCIsICANCiAgICAgICAgbGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiwNCiAgICAgICAgbGVnZW5kLmJveCA9ICJob3Jpem9udGFsIiwgIA0KICAgICAgICBsZWdlbmQuYm94Lmp1c3QgPSAibGVmdCIsICANCiAgICAgICAgbGVnZW5kLnRpdGxlLmFsaWduID0gMC41LCAgDQogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMSwgImNtIiksICANCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPTI1KSwNCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDI1KSwgIA0KICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCksDQogICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpICsgIA0KICB5bGFiKCJQZXJjZW50YWdlIikgKyANCiAgeGxhYigiQ0VFU0FUIFF1ZXN0aW9uIikgKw0KICBmYWNldF93cmFwKH5iaW5hcnlfZ3VpZGVsaW5lKSANCg0KY2Vlc2F0X3JlcG9ydA0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJjZWVzYXRfcmVwb3J0LnBkZiIpLCB3aWR0aCA9IDI1LCBoZWlnaHQgPSAxNSwgdW5pdHMgPSAiY20iLCBzY2FsZSA9IDIsIGRwaSA9IDgwMCkNCiMgZ2dzYXZlKGhlcmUoImZpZ3VyZXMiLCAiY2Vlc2F0X3JlcG9ydC5qcGciKSwgd2lkdGggPSAyNSwgaGVpZ2h0ID0gMTUsIHVuaXRzID0gImNtIiwgc2NhbGUgPSAyLCBkcGkgPSA4MDApDQoNCmd1aWRlbGluZSA8LSBzZF9iaWJfYWx0X2d1aWRlbGluZSR0b3RhbF9wb2ludHNbc2RfYmliX2FsdF9ndWlkZWxpbmUkYmluYXJ5X2d1aWRlbGluZSA9PSAiUmVwb3J0ZWQiXQ0Kbm9fZ3VpZGVsaW5lIDwtIHNkX2JpYl9hbHRfZ3VpZGVsaW5lJHRvdGFsX3BvaW50c1tzZF9iaWJfYWx0X2d1aWRlbGluZSRiaW5hcnlfZ3VpZGVsaW5lID09ICJOb3QgcmVwb3J0ZWQiXQ0KDQoNCiMgQ3JlYXRlIGEgdGliYmxlIGZvciBwb2xpY3kgdmFsdWVzDQpndWlkZWxpbmVfZGYgPC0gdGliYmxlKA0KICB2YWx1ZXMgPSBndWlkZWxpbmUsDQogIGNhdGVnb3J5ID0gIkNpdGVkIEd1aWRlbGluZSINCikNCg0KIyBDcmVhdGUgYSB0aWJibGUgZm9yIG5vdF9wb2xpY3kgdmFsdWVzDQpub19ndWlkZWxpbmVfZGYgPC0gdGliYmxlKA0KICB2YWx1ZXMgPSBub19ndWlkZWxpbmUsDQogIGNhdGVnb3J5ID0gIk5vIEd1aWRlbGluZSINCikNCg0KIyBDb21iaW5lIGJvdGggdGliYmxlcyBpbnRvIG9uZQ0KZ3VpZGVsaW5lX2NvbWJpbmVkIDwtIGJpbmRfcm93cyhndWlkZWxpbmVfZGYsIG5vX2d1aWRlbGluZV9kZikNCg0KIyBWaWV3IHRoZSBjb21iaW5lZCB0aWJibGUNCnByaW50KGd1aWRlbGluZV9jb21iaW5lZCkNCg0KDQoNCmd1aWRlbGluZV9tb2RlbCA8LSBjbG0oZmFjdG9yKHZhbHVlcykgfiBjYXRlZ29yeSwgZGF0YT1ndWlkZWxpbmVfY29tYmluZWQpDQoNCnN1bW1hcnkoZ3VpZGVsaW5lX21vZGVsKQ0KDQogDQoNCnQudGVzdChndWlkZWxpbmUsbm9fZ3VpZGVsaW5lKQ0KDQoNCmBgYA0KDQojIyBTY2F0dGVyIHBsb3QgcG9saWN5ICYgcXVhbGl0eQ0KU2NhdHRlciBwbG90IHNob3dpbmcgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBxdWFudGl0eSBvZiB0aW1lcyBjaXRlZCBpbiBhIHBvbGljeSBkb2N1bWVudCBhbmQgdG90YWwgQ0VFU0FUIHNjb3JlIA0KYGBge3IsIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD0xMn0NCiMgQ3JlYXRlIHRoZSBwbG90IA0KcG9saWN5X3F1YWxpdHkgPC0gc2RfYmliX2FsdF9wb2xpY3kgJT4lDQogIyBmaWx0ZXIodG90YWxfcG9pbnRzICE9IDAsIHBvbGljeSAhPSAwKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IHRvdGFsX3BvaW50cywgeSA9IHBvbGljeSkpICsNCiAgZ2VvbV9wb2ludChjb2xvciA9ICIjMWI5ZTc3IiwgYWxwaGEgPSAwLjgsIHNpemUgPSA4KSArDQogIGdlb21fc21vb3RoKG1ldGhvZCA9IGxtLCBzZSA9IFRSVUUsIGNvbG9yID0gInJlZCIpICsNCiAgbGFicyh4ID0gIlRvdGFsIENFRVNBVCBzY29yZSIsIHkgPSAiUG9saWN5IENvdW50IikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMubGluZS55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyNSksDQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyNSksDQogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMzApLA0KICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMwKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkNCg0KcG9saWN5X3F1YWxpdHkNCg0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJwb2xpY3lfcXVhbGl0eS5wZGYiKSwgd2lkdGggPSAyNSwgaGVpZ2h0ID0gMTUsIHVuaXRzID0gImNtIiwgc2NhbGUgPSAyLCBkcGkgPSA4MDApDQojIGdnc2F2ZShoZXJlKCJmaWd1cmVzIiwgInBvbGljeV9xdWFsaXR5LmpwZyIpLCB3aWR0aCA9IDI1LCBoZWlnaHQgPSAxNSwgdW5pdHMgPSAiY20iLCBzY2FsZSA9IDIsIGRwaSA9IDgwMCkNCmBgYA0KDQoNCiMjIEJveCBjZWVzYXQgc2NvcmVzDQpCb3ggYW5kIHZpb2xpbiBwbG90IHNob3dpbmcgdGhlIGRpc3RyaWJ1dGlvbiBvZiBDRUVTQVQgc2NvcmVzIGZvciBzdHVkaWVzIGNpdGVkIGluIHBvbGljeSBkb2N1bWVudHMgYW5kIHN0dWRpZXMgbm90IGNpdGVkIGluIHBvbGljeSBkb2N1bWVudHMNCmBgYHtyLCBmaWcud2lkdGg9MjUsIGZpZy5oZWlnaHQ9MTV9DQpib3hfY2Vlc2F0IDwtIHBvbGljeV9jb21iaW5lZCAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gY2F0ZWdvcnksIHkgPSB2YWx1ZXMpKSArDQogIGdlb21fdmlvbGluKGZpbGwgPSAiIzFiOWU3NyIsIGFscGhhID0wLjIsIGNvbG9yID0gTkEsIHRyaW0gPSBGQUxTRSkgKw0KICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjA1LCBmaWxsID0gIndoaXRlIiwgY29sb3IgPSAiIzFiOWU3NyIsIG91dGxpZXIuc2hhcGUgPSBOQSkgKw0KICBnZW9tX2ppdHRlcih3aWR0aCA9IDAuMSwgaGVpZ2h0ID0gMC4wNSwgY29sb3IgPSAiIzFiOWU3NyIsIGFscGhhID0gMC44LCBzaXplID0gNikgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCBtYXgoc2QkdG90YWxfcG9pbnRzKSkpICsNCiAgbGFicyggeCA9ICJQb2xpY3kiLCB5ID0gIlRvdGFsIENFRVNBVCBTY29yZSIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLmxpbmUueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMjUpLA0KICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjUpLA0KICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMwKSwNCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMCksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpDQoNCmJveF9jZWVzYXQNCg0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJib3hfY2Vlc2F0LnBkZiIpLCB3aWR0aCA9IDI1LCBoZWlnaHQgPSAxNSwgdW5pdHMgPSAiY20iLCBzY2FsZSA9IDIsIGRwaSA9IDgwMCkNCiMgZ2dzYXZlKGhlcmUoImZpZ3VyZXMiLCAiYm94X2NlZXNhdC5qcGciKSwgd2lkdGggPSAyNSwgaGVpZ2h0ID0gMTUsIHVuaXRzID0gImNtIiwgc2NhbGUgPSAyLCBkcGkgPSA4MDApDQpgYGANCg0KDQojIyBBbGx1dmlhbCBwbG90IGZvciBiaWFzIGFzc2Vzc21lbnQNCkFsbHV2aWFsIHBsb3Qgc2hvd2luZyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIEpvdXJuYWwgQ2l0YXRpb24gUmVwb3J0IENhdGVnb3J5IGFuZCBiaWFzIGFzc2Vzc21lbnQgbWV0aG9kLg0KYGBge3IsIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD0xMH0NCiMgRGF0YSBUcmFuc2Zvcm1hdGlvbiANCmJpYXNfYXNzZXNzbWVudF9hbGx1dmlhbCA8LSBzZCAlPiUgDQogICAgc2VwYXJhdGVfcm93cyhiaWFzX2Fzc2Vzc21lbnRfbWV0aG9kLCBzZXAgPSAiLFxccysiKSAlPiUNCiAgICBzZXBhcmF0ZV9yb3dzKEpvdXJuYWxfQ2F0ZWdvcnlfQWxsb2NhdGVkX0Jyb2FkLCBzZXAgPSAiL1xccysiKSAlPiUgDQogICAgZmlsdGVyKCFpcy5uYShiaWFzX2Fzc2Vzc21lbnRfbWV0aG9kKSkgJT4lDQogICAgZ3JvdXBfYnkoSm91cm5hbF9DYXRlZ29yeV9BbGxvY2F0ZWRfQnJvYWQsIGJpYXNfYXNzZXNzbWVudF9tZXRob2QpICU+JSANCiAgICBjb3VudChiaWFzX2Fzc2Vzc21lbnRfbWV0aG9kLCBKb3VybmFsX0NhdGVnb3J5X0FsbG9jYXRlZF9Ccm9hZCkgJT4lIA0KICAgIHN1bW1hcmlzZShmcmVxID0gbigpLCAuZ3JvdXBzID0gJ2Ryb3AnKSAlPiUgDQogICAgZ3JvdXBfYnkoYmlhc19hc3Nlc3NtZW50X21ldGhvZCkNCg0KIyBDcmVhdGUgdGhlIEFsbHV2aWFsIHBsb3QNCmFsbHV2aWFsX2JpYXMgPC0gYmlhc19hc3Nlc3NtZW50X2FsbHV2aWFsICU+JSANCiAgZ2dwbG90KGFlcyh5ID0gZnJlcSAsYXhpczEgPSBKb3VybmFsX0NhdGVnb3J5X0FsbG9jYXRlZF9Ccm9hZCwgYXhpczIgPSBiaWFzX2Fzc2Vzc21lbnRfbWV0aG9kKSkgKw0KICBzY2FsZV94X2Rpc2NyZXRlKGxpbWl0cyA9IGMoIkpvdXJuYWwgQ2l0YXRpb24gQ2F0ZWdvcnkiLCAiQmlhcyBBc3Nlc3NtZW50IiksIGV4cGFuZCA9IGMoLjA1LCAuMDUpKSArDQogIHhsYWIoIlZhcmlhYmxlcyIpICsNCiAgZ2VvbV9hbGx1dml1bShhZXMoZmlsbCA9IEpvdXJuYWxfQ2F0ZWdvcnlfQWxsb2NhdGVkX0Jyb2FkKSkgKw0KICBnZW9tX3N0cmF0dW0od2lkdGggPSAxLzMuNSwgZmlsbCA9ICJ3aGl0ZSIsIGNvbG9yID0gImJsYWNrIikgKw0KICBnZW9tX3RleHQoc3RhdCA9ICJzdHJhdHVtIiwgYWVzKGxhYmVsID0gYWZ0ZXJfc3RhdChzdHJhdHVtKSksIHNpemUgPSA2KSArDQogIGxhYnMoeD0gIlZhcmlhYmxlcyIsIHkgPSAiRnJlcXVlbmN5IiwgZmlsbCA9ICJKb3VybmFsIENhdGVnb3J5IEFsbG9jYXRlZCIpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpICsNCiAgb3JnYW5vY2hsb3JUSEVNRSgpIA0KDQphbGx1dmlhbF9iaWFzDQoNCiMgZ2dzYXZlKGhlcmUoImZpZ3VyZXMiLCAiYWxsdXZpYWxfYmlhcy5wZGYiKSwgd2lkdGggPSAxNiwgaGVpZ2h0ID0gMTAsIHVuaXRzID0gImNtIiwgc2NhbGUgPSAyLCBkcGkgPSA4MDApDQojIGdnc2F2ZShoZXJlKCJmaWd1cmVzIiwgImFsbHV2aWFsX2JpYXMuanBnIiksIHdpZHRoID0gMTYsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KDQpgYGANCg0KIyMgQWxsdXZpYWwgcGxvdCBmb3IgSGV0ZXJvZ2VuZWl0eQ0KQWxsdXZpYWwgcGxvdCBzaG93aW5nIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgSm91cm5hbCBDaXRhdGlvbiBSZXBvcnQgQ2F0ZWdvcnkgYW5kIGhldGVyb2dlbmVpdHkgYXNzZXNzbWVudCBtZXRob2QuDQpgYGB7ciwgZmlnLndpZHRoPTE2LCBmaWcuaGVpZ2h0PTEwfQ0KIyBEYXRhIFRyYW5zZm9ybWF0aW9uIA0KaGV0ZXJvZ2VuZWl0eV9hbGx1dmlhbCA8LSBzZCAlPiUgDQogICAgc2VwYXJhdGVfcm93cyhoZXRlcm9nZW5laXR5X2Fzc2Vzc21lbnRfbWV0aG9kLCBzZXAgPSAiLFxccysiKSAlPiUNCiAgICBzZXBhcmF0ZV9yb3dzKEpvdXJuYWxfQ2F0ZWdvcnlfQWxsb2NhdGVkX0Jyb2FkLCBzZXAgPSAiL1xccysiKSAlPiUgDQogICAgZmlsdGVyKCFpcy5uYShoZXRlcm9nZW5laXR5X2Fzc2Vzc21lbnRfbWV0aG9kKSkgJT4lDQogICAgZ3JvdXBfYnkoSm91cm5hbF9DYXRlZ29yeV9BbGxvY2F0ZWRfQnJvYWQsIGhldGVyb2dlbmVpdHlfYXNzZXNzbWVudF9tZXRob2QpICU+JSANCiAgICBjb3VudChoZXRlcm9nZW5laXR5X2Fzc2Vzc21lbnRfbWV0aG9kLCBKb3VybmFsX0NhdGVnb3J5X0FsbG9jYXRlZF9Ccm9hZCkgJT4lIA0KICAgIHN1bW1hcmlzZShmcmVxID0gbigpLCAuZ3JvdXBzID0gJ2Ryb3AnKSAlPiUgDQogICAgZ3JvdXBfYnkoaGV0ZXJvZ2VuZWl0eV9hc3Nlc3NtZW50X21ldGhvZCkgDQoNCiMgQ3JlYXRlIHRoZSBBbGx1dmlhbCBwbG90DQphbGx1dmlhbF9oZXQgPC0gaGV0ZXJvZ2VuZWl0eV9hbGx1dmlhbCAlPiUgDQpnZ3Bsb3QoYWVzKHkgPSBmcmVxICxheGlzMSA9IEpvdXJuYWxfQ2F0ZWdvcnlfQWxsb2NhdGVkX0Jyb2FkLCBheGlzMiA9IGhldGVyb2dlbmVpdHlfYXNzZXNzbWVudF9tZXRob2QpKSArDQogIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gYygiSm91cm5hbCBDaXRhdGlvbiBDYXRlZ29yeSIsICJIZXRlcm9nZW5laXR5IiksIGV4cGFuZCA9IGMoLjA1LCAuMDUpKSArDQogIHhsYWIoIlZhcmlhYmxlcyIpICsNCiAgZ2VvbV9hbGx1dml1bShhZXMoZmlsbCA9IEpvdXJuYWxfQ2F0ZWdvcnlfQWxsb2NhdGVkX0Jyb2FkKSkgKw0KICBnZW9tX3N0cmF0dW0od2lkdGggPSAxLzQuNSwgZmlsbCA9ICJ3aGl0ZSIsIGNvbG9yID0gImJsYWNrIikgKw0KICBnZW9tX3RleHQoc3RhdCA9ICJzdHJhdHVtIiwgYWVzKGxhYmVsID0gYWZ0ZXJfc3RhdChzdHJhdHVtKSksIHNpemUgPSA2KSArDQogIGxhYnMoeD0gIlZhcmlhYmxlcyIsIHkgPSAiRnJlcXVlbmN5IiwgZmlsbCA9ICJKb3VybmFsIENhdGVnb3J5IEFsbG9jYXRlZCIpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpICsNCiAgb3JnYW5vY2hsb3JUSEVNRSgpIA0KDQphbGx1dmlhbF9oZXQNCg0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJhbGx1dmlhbF9oZXQucGRmIiksIHdpZHRoID0gMTYsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJhbGx1dmlhbF9oZXQuanBnIiksIHdpZHRoID0gMTYsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KYGBgDQogDQojIyBGaWd1cmUgczEwDQpBbGx1dmlhbCBwbG90IHNob3dpbmcgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBKb3VybmFsIENpdGF0aW9uIFJlcG9ydCBDYXRlZ29yeSBhbmQgc2Vuc2l0aXZpdHkgYW5hbHlzaXMuDQpgYGB7ciwgZmlnLndpZHRoPTE2LCBmaWcuaGVpZ2h0PTEwfQ0KIyBEYXRhIFRyYW5zZm9ybWF0aW9uIA0Kc2Vuc2l0aXZpdHlfYW5hbHlzaXNfYWxsdXZpYWwgPC0gc2QgJT4lIA0KICAgIHNlcGFyYXRlX3Jvd3Moc2Vuc2l0aXZpdHlfYW5hbHlzaXNfbWV0aG9kLCBzZXAgPSAiLFxccysiKSAlPiUNCiAgICBzZXBhcmF0ZV9yb3dzKEpvdXJuYWxfQ2F0ZWdvcnlfQWxsb2NhdGVkX0Jyb2FkLCBzZXAgPSAiL1xccysiKSAlPiUgDQogICAgZmlsdGVyKCFpcy5uYShzZW5zaXRpdml0eV9hbmFseXNpc19tZXRob2QpKSAlPiUNCiAgICBncm91cF9ieShKb3VybmFsX0NhdGVnb3J5X0FsbG9jYXRlZF9Ccm9hZCwgc2Vuc2l0aXZpdHlfYW5hbHlzaXNfbWV0aG9kKSAlPiUgDQogICAgY291bnQoc2Vuc2l0aXZpdHlfYW5hbHlzaXNfbWV0aG9kLCBKb3VybmFsX0NhdGVnb3J5X0FsbG9jYXRlZF9Ccm9hZCkgJT4lIA0KICAgIHN1bW1hcmlzZShmcmVxID0gbigpLCAuZ3JvdXBzID0gJ2Ryb3AnKSAlPiUgDQogICAgZ3JvdXBfYnkoc2Vuc2l0aXZpdHlfYW5hbHlzaXNfbWV0aG9kKQ0KDQojIENyZWF0ZSB0aGUgQWxsdXZpYWwgcGxvdA0KYWxsdXZpYWxfc2VucyA8LSBzZW5zaXRpdml0eV9hbmFseXNpc19hbGx1dmlhbCAlPiUgDQpnZ3Bsb3QoYWVzKHkgPSBmcmVxICxheGlzMSA9IEpvdXJuYWxfQ2F0ZWdvcnlfQWxsb2NhdGVkX0Jyb2FkLCBheGlzMiA9IHNlbnNpdGl2aXR5X2FuYWx5c2lzX21ldGhvZCkpICsNCiAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSBjKCJKb3VybmFsIENpdGF0aW9uIENhdGVnb3J5IiwgIlNlbnNpdGl2aXR5IEFuYWx5c2lzIiksIGV4cGFuZCA9IGMoLjA1LCAuMDUpKSArDQogIHhsYWIoIlZhcmlhYmxlcyIpICsNCiAgZ2VvbV9hbGx1dml1bShhZXMoZmlsbCA9IEpvdXJuYWxfQ2F0ZWdvcnlfQWxsb2NhdGVkX0Jyb2FkKSkgKw0KICBnZW9tX3N0cmF0dW0od2lkdGggPSAxLzQsIGZpbGwgPSAid2hpdGUiLCBjb2xvciA9ICJibGFjayIpICsNCiAgZ2VvbV90ZXh0KHN0YXQgPSAic3RyYXR1bSIsIGFlcyhsYWJlbCA9IGFmdGVyX3N0YXQoc3RyYXR1bSkpLCBzaXplID0gNSkgKw0KICBsYWJzKHg9ICJWYXJpYWJsZXMiLCB5ID0gIkZyZXF1ZW5jeSIsIGZpbGwgPSAiSm91cm5hbCBDYXRlZ29yeSBBbGxvY2F0ZWQiKSArDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiKSArDQogIG9yZ2Fub2NobG9yVEhFTUUoKSANCg0KYWxsdXZpYWxfc2Vucw0KDQojIGdnc2F2ZShoZXJlKCJmaWd1cmVzIiwgImFsbHV2aWFsX3NlbnMucGRmIiksIHdpZHRoID0gMTYsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJhbGx1dmlhbF9zZW5zLmpwZyIpLCB3aWR0aCA9IDE2LCBoZWlnaHQgPSAxMCwgdW5pdHMgPSAiY20iLCBzY2FsZSA9IDIsIGRwaSA9IDgwMCkNCg0KYGBgDQoNCiMjIEFsbHV2aWFsIHBsb3QgZm9yIHJlcG9ydGluZyBndWlkZWxpbmUNCkFuIGFsbHV2aWFsIHBsb3Qgc2hvd2luZyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIEpvdXJuYWwgQ2l0YXRpb24gUmVwb3J0IENhdGVnb3J5IGFuZCByZXBvcnRpbmcgZ3VpZGVsaW5lIHVzZWQgDQpgYGB7ciwgZmlnLndpZHRoPTE2LCBmaWcuaGVpZ2h0PTEwfQ0KIyBEYXRhIFRyYW5zZm9ybWF0aW9uIA0KcmVwb3J0aW5nX3N0YW5kYXJkc19hbGx1dmlhbCA8LSBzZCAlPiUgDQogICAgc2VwYXJhdGVfcm93cyhyZXBvcnRpbmdfc3RhbmRhcmRzX3R5cGUsIHNlcCA9ICIsXFxzKyIpICU+JQ0KICAgIHNlcGFyYXRlX3Jvd3MoSm91cm5hbF9DYXRlZ29yeV9BbGxvY2F0ZWRfQnJvYWQsIHNlcCA9ICIvXFxzKyIpICU+JQ0KICAgIGZpbHRlcighZ3JlcGwoIm5vIGNhdGVnb3J5IGZvdW5kIiwgSm91cm5hbF9DYXRlZ29yeV9BbGxvY2F0ZWRfQnJvYWQsIGlnbm9yZS5jYXNlID0gVFJVRSkpICU+JSANCiAgICBmaWx0ZXIoIWlzLm5hKHJlcG9ydGluZ19zdGFuZGFyZHNfdHlwZSkpICU+JQ0KICAgIGdyb3VwX2J5KEpvdXJuYWxfQ2F0ZWdvcnlfQWxsb2NhdGVkX0Jyb2FkLCByZXBvcnRpbmdfc3RhbmRhcmRzX3R5cGUpICU+JSANCiAgICBjb3VudChyZXBvcnRpbmdfc3RhbmRhcmRzX3R5cGUsIEpvdXJuYWxfQ2F0ZWdvcnlfQWxsb2NhdGVkX0Jyb2FkKSAlPiUgDQogICAgc3VtbWFyaXNlKGZyZXEgPSBuKCksIC5ncm91cHMgPSAnZHJvcCcpICU+JSANCiAgICBncm91cF9ieShyZXBvcnRpbmdfc3RhbmRhcmRzX3R5cGUpDQoNCiMgQ3JlYXRlIHRoZSBBbGx1dmlhbCBwbG90DQphbGx1dmlhbF9yZXBvcnQgPC0gcmVwb3J0aW5nX3N0YW5kYXJkc19hbGx1dmlhbCAlPiUgDQpnZ3Bsb3QoIGFlcyh5ID0gZnJlcSAsYXhpczEgPSBKb3VybmFsX0NhdGVnb3J5X0FsbG9jYXRlZF9Ccm9hZCwgYXhpczIgPSByZXBvcnRpbmdfc3RhbmRhcmRzX3R5cGUpKSArDQogIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gYygiSm91cm5hbCBDaXRhdGlvbiBDYXRlZ29yeSIsICJSZXBvcnRpbmcgU3RhbmRhcmRzIFR5cGUiKSwgZXhwYW5kID0gYyguMDUsIC4wNSkpICsNCiAgeGxhYigiVmFyaWFibGVzIikgKw0KICBnZW9tX2FsbHV2aXVtKGFlcyhmaWxsID0gSm91cm5hbF9DYXRlZ29yeV9BbGxvY2F0ZWRfQnJvYWQpKSArDQogIGdlb21fc3RyYXR1bSh3aWR0aCA9IDEvMy41LCBmaWxsID0gIndoaXRlIiwgY29sb3IgPSAiYmxhY2siKSArDQogIGxhYnMoeD0gIlZhcmlhYmxlcyIsIHkgPSAiRnJlcXVlbmN5IiwgZmlsbCA9ICJKb3VybmFsIENhdGVnb3J5IEFsbG9jYXRlZCIpICsNCiAgZ2VvbV90ZXh0KHN0YXQgPSAic3RyYXR1bSIsIGFlcyhsYWJlbCA9IGFmdGVyX3N0YXQoc3RyYXR1bSkpLCBzaXplID0gNikgKw0KICAgIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiKSArDQogIG9yZ2Fub2NobG9yVEhFTUUoKSANCg0KYWxsdXZpYWxfcmVwb3J0DQoNCiMgZ2dzYXZlKGhlcmUoImZpZ3VyZXMiLCAiYWxsdXZpYWxfcmVwb3J0LnBkZiIpLCB3aWR0aCA9IDE2LCBoZWlnaHQgPSAxMCwgdW5pdHMgPSAiY20iLCBzY2FsZSA9IDIsIGRwaSA9IDgwMCkNCiMgZ2dzYXZlKGhlcmUoImZpZ3VyZXMiLCAiYWxsdXZpYWxfcmVwb3J0LmpwZyIpLCB3aWR0aCA9IDE2LCBoZWlnaHQgPSAxMCwgdW5pdHMgPSAiY20iLCBzY2FsZSA9IDIsIGRwaSA9IDgwMCkNCmBgYA0KDQoNCiMjIERhdGFiYXNlIGJhciBwbG90DQpCYXIgcGxvdCBzaG93aW5nIHRoZSBwZXJjZW50YWdlIGFuZCB0b3RhbCBjb3VudCBvZiBzY2llbnRpZmljIGxpdGVyYXR1cmUgZGF0YWJhc2VzIHVzZWQgaW4gbWV0YS1hbmFseXNlcyBpbnZlc3RpZ2F0aW5nIHRoZSBpbXBhY3RzIG9mIG9yZ2Fub2NobG9yaW5lIHBlc3RpY2lkZXMuIE5vdGUgdGhhdCBzb21lIG1ldGEtYW5hbHlzZXMgbWF5IGNvbnRyaWJ1dGUgdG8gbXVsdGlwbGUgc2VjdGlvbnMgaWYgdGhlIHN0dWR5IGludm9sdmVkIG11bHRpcGxlIHNjaWVudGlmaWMgbGl0ZXJhdHVyZSBkYXRhYmFzZXMuIFRoZSAiT3RoZXIgZGF0YWJhc2VzIiBjYXRlZ29yeSBpbmNsdWRlcyBhbGwgZGF0YWJhc2VzIHdpdGggYSBjb3VudCBvZiAzIG9yIGxlc3MuIFBlcmNlbnRhZ2UgaXMgc2hvd2luZyB0aGUgcHJvcG9ydGlvbiBvZiBzdHVkaWVzLg0KYGBge3IsIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD0xMH0NCiMgQ2FsY3VsYXRlIHRoZSB0b3RhbCBjb3VudCBmb3IgZWFjaCBjYXRlZ29yeQ0KZGF0YWJhc2VfY291bnQgPC0gc2QgJT4lIA0KICBzZXBhcmF0ZV9yb3dzKGRhdGFiYXNlX3NlYXJjaCwgc2VwID0gIixcXHMrIikgJT4lIA0KICBjb3VudChkYXRhYmFzZV9zZWFyY2gpICU+JSANCiAgZmlsdGVyKGRhdGFiYXNlX3NlYXJjaCAhPSAiTkEiKSAlPiUgDQogIGFycmFuZ2UoZGVzYyhuKSkgJT4lIA0KICBtdXRhdGUoZGF0YWJhc2Vfc2VhcmNoID0gaWZlbHNlKG48PSAzLCAiT3RoZXIgZGF0YWJhc2VzIiwgYXMuY2hhcmFjdGVyKGRhdGFiYXNlX3NlYXJjaCkpKSAlPiUgDQogICAgZ3JvdXBfYnkoZGF0YWJhc2Vfc2VhcmNoKSAlPiUNCiAgc3VtbWFyaXNlKG4gPSBzdW0obikpDQoNCiMgQ2FsY3VsYXRlIHByb3BvcnRpb24gYW5kIHBlcmNlbnRhZ2UgZm9yIGVhY2ggY2F0ZWdvcnkNCmRhdGFiYXNlX3BjdCA8LSBkYXRhYmFzZV9jb3VudCAlPiUNCiAgbXV0YXRlKHByb3BvcnRpb24gPSBuIC8gODMsICMgODMgaXMgbnVtYmVyIG9mIHN0dWRpZXMgYXNzZXNzZWQgZm9yIENFRVNBVA0KICAgICAgICAgcGVyY2VudGFnZSA9IHByb3BvcnRpb24gKiAxMDApDQoNCiMgQ3JlYXRlIHRoZSBjb3VudCBwbG90DQpkYXRhYmFzZV9iYXIgPC0gZGF0YWJhc2VfY291bnQgJT4lDQogIGdncGxvdChhZXMoeCA9IG4sIHkgPSByZW9yZGVyKGRhdGFiYXNlX3NlYXJjaCwgbiksIGZpbGwgPSAiIzFiOWU3NyIpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDAuOCAsIGFscGhhID0gMC43KSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBuLCB4ID0gbiAvIDIsIHkgPSByZW9yZGVyKGRhdGFiYXNlX3NlYXJjaCwgbikpLCBoanVzdCA9IDAuNSwgc2l6ZSA9IDEyLCBjb2xvciA9ICJibGFjayIpICsNCiAgZ2VvbV90ZXh0KGRhdGEgPSBkYXRhYmFzZV9wY3QsIGFlcyhsYWJlbCA9IHBhc3RlMCgiKCIsIHJvdW5kKHBlcmNlbnRhZ2UsIDEpLCAiJSkiKSwgeCA9IG4pLCANCiAgICAgICAgICAgIGhqdXN0ID0gLTAuMSwgc2l6ZSA9IDEyLCBjb2xvciA9ICJibGFjayIsIGZvbnRmYWNlID0gImJvbGQiKSArDQogIHNjYWxlX2ZpbGxfaWRlbnRpdHkoZ3VpZGUgPSAibm9uZSIpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwgMCksIGxpbWl0cyA9IGMoMCwgbWF4KGRhdGFiYXNlX2NvdW50JG4pKjEuMykpICsNCiAgbGFicyh0aXRsZSA9IE5VTEwsIHggPSBOVUxMLCB5ID0gTlVMTCkgKw0KICBvcmdhbm9jaGxvclRIRU1FKCkgDQoNCmRhdGFiYXNlX2Jhcg0KDQojIGdnc2F2ZShoZXJlKCJmaWd1cmVzIiwgImRhdGFiYXNlX2Jhci5wZGYiKSwgd2lkdGggPSAxNiwgaGVpZ2h0ID0gMTAsIHVuaXRzID0gImNtIiwgc2NhbGUgPSAyLCBkcGkgPSA4MDApDQojIGdnc2F2ZShoZXJlKCJmaWd1cmVzIiwgImRhdGFiYXNlX2Jhci5qcGciKSwgd2lkdGggPSAxNiwgaGVpZ2h0ID0gMTAsIHVuaXRzID0gImNtIiwgc2NhbGUgPSAyLCBkcGkgPSA4MDApDQpgYGANCg0KIyMgQWxsdXZpYWwgcGxvdCBmb3IgbGl0ZXJhdHVyZSBkYXRhYmFzZQ0KQWxsdXZpYWwgcGxvdCBzaG93aW5nIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgSm91cm5hbCBDaXRhdGlvbiBSZXBvcnQgQ2F0ZWdvcnkgYW5kIHRoZSBzY2llbnRpZmljIGxpdGVyYXR1cmUgZGF0YWJhc2UgdXNlZC4gRmlsdGVyZWQgZm9yIHNjaWVudGlmaWMgbGl0ZXJhdHVyZSBkYXRhYmFzZSBjb3VudHMgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvIDMuIA0KYGBge3IsIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD0xMH0NCiMgUmVuYW1lIEVudmlyb25tZW50YWwgU2NpZW5jZQ0Kc2QgPC0gc2QgJT4lDQogIG11dGF0ZShKb3VybmFsX0NhdGVnb3J5X0FsbG9jYXRlZF9Ccm9hZCA9IHN0cl9yZXBsYWNlKEpvdXJuYWxfQ2F0ZWdvcnlfQWxsb2NhdGVkX0Jyb2FkLCAiRW52aXJvbm1lbnRhbCBTY2llbmNlIiwgIkVudmlyb25tZW50YWxcblNjaWVuY2UiKSkNCg0KIyBEYXRhIFRyYW5zZm9ybWF0aW9uIA0KZGF0YWJhc2VfYWxsdXZpYWwgPC0gc2QgJT4lIA0KICAgIHNlcGFyYXRlX3Jvd3MoZGF0YWJhc2Vfc2VhcmNoLCBzZXAgPSAiLFxccysiKSAlPiUNCiAgICBncm91cF9ieShKb3VybmFsX0NhdGVnb3J5X0FsbG9jYXRlZF9Ccm9hZCwgZGF0YWJhc2Vfc2VhcmNoKSAlPiUgDQogICAgY291bnQoZGF0YWJhc2Vfc2VhcmNoLCBKb3VybmFsX0NhdGVnb3J5X0FsbG9jYXRlZF9Ccm9hZCkgJT4lIA0KICAgIHN1bW1hcmlzZShmcmVxID0gbigpLCAuZ3JvdXBzID0gJ2Ryb3AnKSAlPiUgDQogICAgZ3JvdXBfYnkoZGF0YWJhc2Vfc2VhcmNoKSAlPiUgDQogICAgZmlsdGVyKHN1bShmcmVxKSA+PSAzKSAlPiUgDQogICAgZmlsdGVyKGRhdGFiYXNlX3NlYXJjaCAhPSAiTkEiKQ0KDQojIENyZWF0ZSB0aGUgQWxsdXZpYWwgcGxvdA0KYWxsdXZpYWxfZGF0YWJhc2UgPC0gZGF0YWJhc2VfYWxsdXZpYWwgJT4lIA0KZ2dwbG90KGFlcyh5ID0gZnJlcSAsYXhpczEgPSBKb3VybmFsX0NhdGVnb3J5X0FsbG9jYXRlZF9Ccm9hZCwgYXhpczIgPSBkYXRhYmFzZV9zZWFyY2gpKSArDQogIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gYygiSm91cm5hbCBDaXRhdGlvbiBSZXBvcnQiLCAiRGF0YWJhc2UgU2VhcmNoIiksIGV4cGFuZCA9IGMoLjA1LCAuMDUpKSArDQogIHhsYWIoIlZhcmlhYmxlcyIpICsNCiAgeWxhYigiRnJlcXVlbmN5IikgKw0KICBnZW9tX2FsbHV2aXVtKGFlcyhmaWxsID0gSm91cm5hbF9DYXRlZ29yeV9BbGxvY2F0ZWRfQnJvYWQpKSArDQogIGdlb21fc3RyYXR1bSh3aWR0aCA9IDEvNC41LCBmaWxsID0gIndoaXRlIiwgY29sb3IgPSAiYmxhY2siKSArDQogIGdlb21fdGV4dChzdGF0ID0gInN0cmF0dW0iLCBhZXMobGFiZWwgPSBhZnRlcl9zdGF0KHN0cmF0dW0pKSwgc2l6ZSA9IDYpICsNCiAgbGFicyh4PSAiVmFyaWFibGVzIiwgeSA9ICJGcmVxdWVuY3kiLCBmaWxsID0gIkpvdXJuYWwgQ2F0ZWdvcnkgQWxsb2NhdGVkIikgKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIikgKw0KICBvcmdhbm9jaGxvclRIRU1FKCkgDQoNCmFsbHV2aWFsX2RhdGFiYXNlDQoNCiMgZ2dzYXZlKGhlcmUoImZpZ3VyZXMiLCAiYWxsdXZpYWxfZGF0YWJhc2UucGRmIiksIHdpZHRoID0gMTYsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJhbGx1dmlhbF9kYXRhYmFzZS5qcGciKSwgd2lkdGggPSAxNiwgaGVpZ2h0ID0gMTAsIHVuaXRzID0gImNtIiwgc2NhbGUgPSAyLCBkcGkgPSA4MDApDQoNCmBgYA0KDQojIyBTb2Z0d2FyZSBiYXIgcGxvdA0KQmFyIHBsb3Qgc2hvd2luZyB0aGUgcGVyY2VudGFnZSBhbmQgdG90YWwgY291bnQgb2Ygc29mdHdhcmUgZm9yIGFuYWx5c2lzIHVzZWQgaW4gbWV0YS1hbmFseXNlcyBpbnZlc3RpZ2F0aW5nIHRoZSBpbXBhY3RzIG9mIG9yZ2Fub2NobG9yaW5lIHBlc3RpY2lkZXMuIE5vdGUgdGhhdCBzb21lIG1ldGEtYW5hbHlzZXMgbWF5IGNvbnRyaWJ1dGUgdG8gbXVsdGlwbGUgc2VjdGlvbnMgaWYgdGhlIHN0dWR5IGludm9sdmVkIG11bHRpcGxlIHNvZnR3YXJlLiBQZXJjZW50YWdlIGlzIHNob3dpbmcgdGhlIHByb3BvcnRpb24gb2Ygc3R1ZGllcy4NCmBgYHtyLCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9MTB9DQojIENhbGN1bGF0ZSB0aGUgdG90YWwgY291bnQgZm9yIGVhY2ggY2F0ZWdvcnkNCnNvZnR3YXJlX2NvdW50IDwtIHNkICU+JQ0KICBzZXBhcmF0ZV9yb3dzKHNvZnR3YXJlX2FuYWx5c2lzLCBzZXAgPSAiLFxccysiKSAlPiUNCiAgbXV0YXRlKHNvZnR3YXJlX2FuYWx5c2lzID0gaWZlbHNlKGdyZXBsKCJjb21wcmVoZW5zaXZlIG1ldGEtYW5hbHlzaXMiLCBzb2Z0d2FyZV9hbmFseXNpcyksICJDTUFTIiwgc29mdHdhcmVfYW5hbHlzaXMpKSAlPiUNCiAgY291bnQoc29mdHdhcmVfYW5hbHlzaXMpICU+JQ0KICBmaWx0ZXIoc29mdHdhcmVfYW5hbHlzaXMgIT0gIk5BIikgJT4lDQogIGFycmFuZ2UoZGVzYyhuKSkgJT4lDQogIG11dGF0ZShzb2Z0d2FyZV9hbmFseXNpcyA9IGlmZWxzZShuIDwgMiwgIk90aGVyIFNvZnR3YXJlIiwgYXMuY2hhcmFjdGVyKHNvZnR3YXJlX2FuYWx5c2lzKSkpICU+JQ0KICBncm91cF9ieShzb2Z0d2FyZV9hbmFseXNpcykgJT4lDQogIHN1bW1hcmlzZShuID0gc3VtKG4pKQ0KDQojIENhbGN1bGF0ZSBwcm9wb3J0aW9uIGFuZCBwZXJjZW50YWdlIGZvciBlYWNoIGNhdGVnb3J5DQpzb2Z0d2FyZV9wY3QgPC0gc29mdHdhcmVfY291bnQgJT4lDQogIG11dGF0ZShwcm9wb3J0aW9uID0gbiAvIDgzLA0KICAgICAgICAgcGVyY2VudGFnZSA9IHByb3BvcnRpb24gKiAxMDApDQoNCiMgQ3JlYXRlIHRoZSBjb3VudCBwbG90DQpzb2Z0d2FyZV9iYXIgPC0gc29mdHdhcmVfY291bnQgJT4lDQogIGdncGxvdChhZXMoeCA9IG4sIHkgPSByZW9yZGVyKHNvZnR3YXJlX2FuYWx5c2lzLCBuKSwgZmlsbCA9ICIjMWI5ZTc3IikpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMC44ICwgYWxwaGEgPSAwLjcpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IG4sIHggPSBuIC8gMiwgeSA9IHJlb3JkZXIoc29mdHdhcmVfYW5hbHlzaXMsIG4pKSwgaGp1c3QgPSAwLjUsIHNpemUgPSAxMiwgY29sb3IgPSAiYmxhY2siKSArDQogIGdlb21fdGV4dChkYXRhID0gc29mdHdhcmVfcGN0LCBhZXMobGFiZWwgPSBwYXN0ZTAoIigiLCByb3VuZChwZXJjZW50YWdlLCAxKSwgIiUpIiksIHggPSBuKSwgDQogICAgICAgICAgICBoanVzdCA9IC0wLjEsIHNpemUgPSAxMiwgY29sb3IgPSAiYmxhY2siLCBmb250ZmFjZSA9ICJib2xkIikgKw0KICBzY2FsZV9maWxsX2lkZW50aXR5KGd1aWRlID0gIm5vbmUiKSArDQogIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBjKDAsIDApLCBsaW1pdHMgPSBjKDAsIG1heChzb2Z0d2FyZV9jb3VudCRuKSoxLjMpKSArDQogIGxhYnModGl0bGUgPSBOVUxMLCB4ID0gTlVMTCwgeSA9IE5VTEwpICsNCiAgb3JnYW5vY2hsb3JUSEVNRSgpIA0KDQpzb2Z0d2FyZV9iYXINCg0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJzb2Z0d2FyZV9iYXIucGRmIiksIHdpZHRoID0gMTYsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJzb2Z0d2FyZV9iYXIuanBnIiksIHdpZHRoID0gMTYsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KDQpgYGANCg0KIyMgQWxsdXZpYWwgcGxvdCBmb3Igc29mdHdhcmUNCkFsbHV2aWFsIHBsb3Qgc2hvd2luZyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIEpvdXJuYWwgQ2l0YXRpb24gUmVwb3J0IENhdGVnb3J5IGFuZCB0aGUgc29mdHdhcmUgdXNlZCBmb3IgYW5hbHlzaXMuDQpgYGB7ciwgZmlnLndpZHRoPTE2LCBmaWcuaGVpZ2h0PTEwfQ0KIyBEYXRhIFRyYW5zZm9ybWF0aW9uIA0Kc29mdHdhcmVfYW5hbHlzaXNfYWxsdXZpYWwgPC0gc2QgJT4lIA0KICAgIHNlcGFyYXRlX3Jvd3Moc29mdHdhcmVfYW5hbHlzaXMsIHNlcCA9ICIsXFxzKyIpICU+JQ0KICAgIHNlcGFyYXRlX3Jvd3MoSm91cm5hbF9DYXRlZ29yeV9BbGxvY2F0ZWRfQnJvYWQsIHNlcCA9ICIvXFxzKyIpICU+JSANCiAgbXV0YXRlKHNvZnR3YXJlX2FuYWx5c2lzID0gaWZlbHNlKGdyZXBsKCJjb21wcmVoZW5zaXZlIG1ldGEtYW5hbHlzaXMiLCBzb2Z0d2FyZV9hbmFseXNpcyksICJDTUFTIiwgc29mdHdhcmVfYW5hbHlzaXMpKSAlPiUNCiAgbXV0YXRlKHNvZnR3YXJlX2FuYWx5c2lzID0gaWZlbHNlKGdyZXBsKCJub3QgcmVwb3J0ZWQiLCBzb2Z0d2FyZV9hbmFseXNpcyksICJubyBzb2Z0d2FyZSByZXBvcnRlZCIsIHNvZnR3YXJlX2FuYWx5c2lzKSkgICU+JSANCiAgICBmaWx0ZXIoIWlzLm5hKHNvZnR3YXJlX2FuYWx5c2lzKSkgJT4lDQogICAgZ3JvdXBfYnkoSm91cm5hbF9DYXRlZ29yeV9BbGxvY2F0ZWRfQnJvYWQsIHNvZnR3YXJlX2FuYWx5c2lzKSAlPiUgDQogICAgY291bnQoc29mdHdhcmVfYW5hbHlzaXMsIEpvdXJuYWxfQ2F0ZWdvcnlfQWxsb2NhdGVkX0Jyb2FkKSAlPiUgDQogICAgc3VtbWFyaXNlKGZyZXEgPSBuKCksIC5ncm91cHMgPSAnZHJvcCcpICU+JSANCiAgICBncm91cF9ieShzb2Z0d2FyZV9hbmFseXNpcykNCg0KIyBDcmVhdGUgdGhlIEFsbHV2aWFsIHBsb3QgZm9yIFNvZnR3YXJlIEFuYWx5c2lzDQphbGx1dmlhbF9zb2Z0d2FyZSA8LSBzb2Z0d2FyZV9hbmFseXNpc19hbGx1dmlhbCAlPiUgDQogIGdncGxvdChhZXMoeSA9IGZyZXEgLGF4aXMxID0gSm91cm5hbF9DYXRlZ29yeV9BbGxvY2F0ZWRfQnJvYWQsIGF4aXMyID0gc29mdHdhcmVfYW5hbHlzaXMpKSArDQogIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gYygiSm91cm5hbCBDaXRhdGlvbiBDYXRlZ29yeSIsICJTb2Z0d2FyZSBBbmFseXNpcyIpLCBleHBhbmQgPSBjKC4wNSwgLjA1KSkgKw0KICB4bGFiKCJWYXJpYWJsZXMiKSArDQogIGdlb21fYWxsdXZpdW0oYWVzKGZpbGwgPSBKb3VybmFsX0NhdGVnb3J5X0FsbG9jYXRlZF9Ccm9hZCkpICsNCiAgZ2VvbV9zdHJhdHVtKHdpZHRoID0gMS80LCBmaWxsID0gIndoaXRlIiwgY29sb3IgPSAiYmxhY2siKSArDQogIGdlb21fdGV4dChzdGF0ID0gInN0cmF0dW0iLCBhZXMobGFiZWwgPSBhZnRlcl9zdGF0KHN0cmF0dW0pKSwgc2l6ZSA9IDYpICsNCiAgbGFicyh4PSAiVmFyaWFibGVzIiwgeSA9ICJGcmVxdWVuY3kiLCBmaWxsID0gIkpvdXJuYWwgQ2F0ZWdvcnkgQWxsb2NhdGVkIikgKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIikgKw0KICBvcmdhbm9jaGxvclRIRU1FKCkgDQoNCmFsbHV2aWFsX3NvZnR3YXJlDQoNCiMgZ2dzYXZlKGhlcmUoImZpZ3VyZXMiLCAiYWxsdXZpYWxfc29mdHdhcmUucGRmIiksIHdpZHRoID0gMTYsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJhbGx1dmlhbF9zb2Z0d2FyZS5qcGciKSwgd2lkdGggPSAxNiwgaGVpZ2h0ID0gMTAsIHVuaXRzID0gImNtIiwgc2NhbGUgPSAyLCBkcGkgPSA4MDApDQpgYGANCg0KIyMgRWZmZWN0IHNpemUgYmFyDQpCYXIgcGxvdCBzaG93aW5nIHRoZSBwZXJjZW50YWdlIGFuZCB0b3RhbCBjb3VudCBvZiBlZmZlY3Qgc2l6ZSBjYWxjdWxhdGlvbiB0eXBlcyB1c2VkIGluIG1ldGEtYW5hbHlzZXMgaW52ZXN0aWdhdGluZyB0aGUgaW1wYWN0cyBvZiBvcmdhbm9jaGxvcmluZSBwZXN0aWNpZGVzLiBOb3RlIHRoYXQgc29tZSBtZXRhLWFuYWx5c2VzIG1heSBjb250cmlidXRlIHRvIG11bHRpcGxlIHNlY3Rpb25zIGlmIHRoZSBzdHVkeSBpbnZvbHZlZCBtdWx0aXBsZSBlZmZlY3Qgc2l6ZSBjYWxjdWxhdGlvbnMuIFRoZSAiT3RoZXIgZWZmZWN0IHNpemVzIiBjYXRlZ29yeSBpbmNsdWRlcyBhbGwgZWZmZWN0IHNpemVzIHdpdGggYSBjb3VudCBvZiAyIG9yIGxlc3MuIFBlcmNlbnRhZ2UgaXMgc2hvd2luZyB0aGUgcHJvcG9ydGlvbiBvZiBzdHVkaWVzLg0KYGBge3IsIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD0xMH0NCiMgQ2FsY3VsYXRlIHRoZSB0b3RhbCBjb3VudCBmb3IgZWFjaCBjYXRlZ29yeQ0KZWZmZWN0c2l6ZV9jb3VudCA8LSBzZCAlPiUgDQogIHNlcGFyYXRlX3Jvd3MoZWZmZWN0X3NpemUsIHNlcCA9ICIsXFxzKyIpICU+JSANCiAgY291bnQoZWZmZWN0X3NpemUpICU+JQ0KICBmaWx0ZXIoZWZmZWN0X3NpemUgIT0gIk5BIikgJT4lDQogIG11dGF0ZShlZmZlY3Rfc2l6ZSA9IGlmZWxzZShuPD0gMiwgIk90aGVyIGVmZmVjdCBzaXplIiwgYXMuY2hhcmFjdGVyKGVmZmVjdF9zaXplKSkpICU+JSANCiAgZ3JvdXBfYnkoZWZmZWN0X3NpemUpICU+JQ0KICBzdW1tYXJpc2UobiA9IHN1bShuKSkNCg0KIyBDYWxjdWxhdGUgcHJvcG9ydGlvbiBhbmQgcGVyY2VudGFnZSBmb3IgZWFjaCBjYXRlZ29yeQ0KZWZmZWN0c2l6ZV9wY3QgPC0gZWZmZWN0c2l6ZV9jb3VudCAlPiUNCiAgbXV0YXRlKHByb3BvcnRpb24gPSBuIC8gODMsDQogICAgICAgICBwZXJjZW50YWdlID0gcHJvcG9ydGlvbiAqIDEwMCkNCg0KIyBDcmVhdGUgdGhlIGNvdW50IHBsb3QNCmVmZmVjdF9iYXIgPC0gIGVmZmVjdHNpemVfY291bnQgJT4lDQogIGdncGxvdChhZXMoeCA9IG4sIHkgPSByZW9yZGVyKGVmZmVjdF9zaXplLCBuKSwgZmlsbCA9ICIjMWI5ZTc3IikpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMC44ICwgYWxwaGEgPSAwLjcpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IG4sIHggPSBuIC8gMiwgeSA9IHJlb3JkZXIoZWZmZWN0X3NpemUsIG4pKSwgaGp1c3QgPSAwLjUsIHNpemUgPSAxMiwgY29sb3IgPSAiYmxhY2siKSArDQogIGdlb21fdGV4dChkYXRhID0gZWZmZWN0c2l6ZV9wY3QsIGFlcyhsYWJlbCA9IHBhc3RlMCgiKCIsIHJvdW5kKHBlcmNlbnRhZ2UsIDEpLCAiJSkiKSwgeCA9IG4pLCANCiAgICAgICAgICAgIGhqdXN0ID0gLTAuMSwgc2l6ZSA9IDEyLCBjb2xvciA9ICJibGFjayIsIGZvbnRmYWNlID0gImJvbGQiKSArDQogIHNjYWxlX2ZpbGxfaWRlbnRpdHkoZ3VpZGUgPSAibm9uZSIpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwgMCksIGxpbWl0cyA9IGMoMCwgbWF4KGVmZmVjdHNpemVfY291bnQkbikqMS4zKSkgKw0KICBsYWJzKHRpdGxlID0gTlVMTCwgeCA9IE5VTEwsIHkgPSBOVUxMKSArDQogIG9yZ2Fub2NobG9yVEhFTUUoKSANCg0KZWZmZWN0X2Jhcg0KDQojIGdnc2F2ZShoZXJlKCJmaWd1cmVzIiwgImVmZmVjdF9iYXIucGRmIiksIHdpZHRoID0gMTYsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJlZmZlY3RfYmFyLmpwZyIpLCB3aWR0aCA9IDE2LCBoZWlnaHQgPSAxMCwgdW5pdHMgPSAiY20iLCBzY2FsZSA9IDIsIGRwaSA9IDgwMCkNCmBgYA0KDQojIyBBbGx1dmlhbCBwbG90IGZvciBlZmZlY3Qgc2l6ZSBlc3RpbWF0ZXMNCkFsbHV2aWFsIHBsb3Qgc2hvd2luZyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIEpvdXJuYWwgQ2l0YXRpb24gUmVwb3J0IENhdGVnb3J5IGFuZCB0aGUgZWZmZWN0IHNpemUgdXNlZC4gRmlsdGVyZWQgZm9yIHNjaWVudGlmaWMgbGl0ZXJhdHVyZSBkYXRhYmFzZSBjb3VudHMgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvIDMuDQpgYGB7ciwgZmlnLndpZHRoPTE2LCBmaWcuaGVpZ2h0PTEwfQ0KIyBEYXRhIFRyYW5zZm9ybWF0aW9uIA0KZWZmZWN0c2l6ZV9hbGx1dmlhbCA8LSBzZCAlPiUgDQogICAgc2VwYXJhdGVfcm93cyhlZmZlY3Rfc2l6ZSwgc2VwID0gIixcXHMrIikgJT4lDQogICAgc2VwYXJhdGVfcm93cyhKb3VybmFsX0NhdGVnb3J5X0FsbG9jYXRlZF9Ccm9hZCwgc2VwID0gIi9cXHMrIikgJT4lIA0KICAgIGZpbHRlcighZ3JlcGwoIm5vIGNhdGVnb3J5IGZvdW5kIiwgSm91cm5hbF9DYXRlZ29yeV9BbGxvY2F0ZWRfQnJvYWQsIGlnbm9yZS5jYXNlID0gVFJVRSkpICU+JSANCiAgICBmaWx0ZXIoIWlzLm5hKGVmZmVjdF9zaXplKSkgJT4lDQogICAgZ3JvdXBfYnkoSm91cm5hbF9DYXRlZ29yeV9BbGxvY2F0ZWRfQnJvYWQsIGVmZmVjdF9zaXplKSAlPiUgDQogICAgY291bnQoZWZmZWN0X3NpemUsIEpvdXJuYWxfQ2F0ZWdvcnlfQWxsb2NhdGVkX0Jyb2FkKSAlPiUgDQogICAgc3VtbWFyaXNlKGZyZXEgPSBuKCksIC5ncm91cHMgPSAnZHJvcCcpICU+JSANCiAgICBncm91cF9ieShlZmZlY3Rfc2l6ZSkgDQoNCg0KIyBDcmVhdGUgdGhlIEFsbHV2aWFsIHBsb3QNCmFsbHV2aWFsX2VmZmVjdCA8LSBlZmZlY3RzaXplX2FsbHV2aWFsICU+JSANCmdncGxvdChhZXMoeSA9IGZyZXEgLGF4aXMxID0gSm91cm5hbF9DYXRlZ29yeV9BbGxvY2F0ZWRfQnJvYWQsIGF4aXMyID0gZWZmZWN0X3NpemUpKSArDQogIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gYygiSm91cm5hbCBDaXRhdGlvbiBDYXRlZ29yeSIsICJFZmZlY3QgU2l6ZSIpLCBleHBhbmQgPSBjKC4wNSwgLjA1KSkgKw0KICB4bGFiKCJWYXJpYWJsZXMiKSArDQogIGdlb21fYWxsdXZpdW0oYWVzKGZpbGwgPSBKb3VybmFsX0NhdGVnb3J5X0FsbG9jYXRlZF9Ccm9hZCkpICsNCiAgZ2VvbV9zdHJhdHVtKHdpZHRoID0gMS8yLjUsIGZpbGwgPSAid2hpdGUiLCBjb2xvciA9ICJibGFjayIpICsNCiAgZ2VvbV90ZXh0KHN0YXQgPSAic3RyYXR1bSIsIGFlcyhsYWJlbCA9IGFmdGVyX3N0YXQoc3RyYXR1bSkpLCBzaXplID0gNSkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBsYWJzKHg9ICJWYXJpYWJsZXMiLCB5ID0gIkZyZXF1ZW5jeSIsIGZpbGwgPSAiSm91cm5hbCBDYXRlZ29yeSBBbGxvY2F0ZWQiKSArDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiKSArDQogIG9yZ2Fub2NobG9yVEhFTUUoKSANCiAgDQphbGx1dmlhbF9lZmZlY3QNCg0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJhbGx1dmlhbF9lZmZlY3QucGRmIiksIHdpZHRoID0gMTYsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJhbGx1dmlhbF9lZmZlY3QuanBnIiksIHdpZHRoID0gMTYsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KYGBgDQoNCiMjIEJhciBwbG90IGZvciB2aXN1YWxpc2F0aW9uIG1ldGhvZA0KQmFyIHBsb3Qgc2hvd2luZyB0aGUgcGVyY2VudGFnZSBhbmQgdG90YWwgY291bnQgb2YgdmlzdWFsaXphdGlvbiBtZXRob2RzIHVzZWQgaW4gbWV0YS1hbmFseXNlcyBpbnZlc3RpZ2F0aW5nIHRoZSBpbXBhY3RzIG9mIG9yZ2Fub2NobG9yaW5lIHBlc3RpY2lkZXMuIE5vdGUgdGhhdCBzb21lIG1ldGEtYW5hbHlzZXMgbWF5IGNvbnRyaWJ1dGUgdG8gbXVsdGlwbGUgc2VjdGlvbnMgaWYgdGhlIHN0dWR5IGludm9sdmVkIHRoZSB1c2Ugb2YgbXVsdGlwbGUgdmlzdWFsaXphdGlvbiBtZXRob2RzLg0KYGBge3IsIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD0xMH0NCiMgQ2FsY3VsYXRlIHRoZSB0b3RhbCBjb3VudCBmb3IgZWFjaCBjYXRlZ29yeQ0KdmlzdWFsaXphdGlvbl9jb3VudCA8LSBzZCAlPiUgDQogIHNlcGFyYXRlX3Jvd3ModmlzdWFsaXphdGlvbl9tZXRob2QsIHNlcCA9ICIsXFxzKyIpICU+JSANCiAgY291bnQodmlzdWFsaXphdGlvbl9tZXRob2QpICU+JQ0KICBmaWx0ZXIodmlzdWFsaXphdGlvbl9tZXRob2QgIT0gIk5BIikgJT4lDQogICAgZ3JvdXBfYnkodmlzdWFsaXphdGlvbl9tZXRob2QpICU+JQ0KICBzdW1tYXJpc2UobiA9IHN1bShuKSkNCg0KIyBDYWxjdWxhdGUgcHJvcG9ydGlvbiBhbmQgcGVyY2VudGFnZSBmb3IgZWFjaCBjYXRlZ29yeQ0KdmlzdWFsaXphdGlvbl9wY3QgPC0gdmlzdWFsaXphdGlvbl9jb3VudCAlPiUNCiAgbXV0YXRlKHByb3BvcnRpb24gPSBuIC8gODMsDQogICAgICAgICBwZXJjZW50YWdlID0gcHJvcG9ydGlvbiAqIDEwMCkNCg0KIyBDcmVhdGUgdGhlIGNvdW50IHBsb3QNCmJhcl92aXMgPC0gdmlzdWFsaXphdGlvbl9jb3VudCAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gbiwgeSA9IHJlb3JkZXIodmlzdWFsaXphdGlvbl9tZXRob2QsIG4pLCBmaWxsID0gaWZlbHNlKGdyZXBsKCJOb3QgcmVwb3J0ZWQiLCB2aXN1YWxpemF0aW9uX21ldGhvZCksICIjNzM3MGIzIiwgIiMxYjllNzciKSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMC44ICwgYWxwaGEgPSAwLjcpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IG4sIHggPSBuIC8gMiwgeSA9IHJlb3JkZXIodmlzdWFsaXphdGlvbl9tZXRob2QsIG4pKSwgaGp1c3QgPSAwLjUsIHNpemUgPSAxMiwgY29sb3IgPSAiYmxhY2siKSArDQogIGdlb21fdGV4dChkYXRhID0gdmlzdWFsaXphdGlvbl9wY3QsIGFlcyhsYWJlbCA9IHBhc3RlMCgiKCIsIHJvdW5kKHBlcmNlbnRhZ2UsIDApLCAiJSkiKSwgeCA9IG4pLCANCiAgICAgICAgICAgIGhqdXN0ID0gLTAuMSwgc2l6ZSA9IDEyLCBjb2xvciA9ICJibGFjayIsIGZvbnRmYWNlID0gImJvbGQiKSArDQogIHNjYWxlX2ZpbGxfaWRlbnRpdHkoZ3VpZGUgPSAibm9uZSIpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwgMCksIGxpbWl0cyA9IGMoMCwgbWF4KHZpc3VhbGl6YXRpb25fY291bnQkbikqMS4zKSkgKw0KICBsYWJzKHRpdGxlID0gTlVMTCwgeCA9IE5VTEwsIHkgPSBOVUxMKSArDQogIG9yZ2Fub2NobG9yVEhFTUUoKSANCg0KYmFyX3Zpcw0KDQojIGdnc2F2ZShoZXJlKCJmaWd1cmVzIiwgImJhcl92aXMucGRmIiksIHdpZHRoID0gMTYsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJiYXJfdmlzLmpwZyIpLCB3aWR0aCA9IDE2LCBoZWlnaHQgPSAxMCwgdW5pdHMgPSAiY20iLCBzY2FsZSA9IDIsIGRwaSA9IDgwMCkNCmBgYA0KDQojIyBBbGx1dmlhbCBwbG90IGZvciB2aXN1YWxpc2F0aW9uIG1ldGhvZA0KQWxsdXZpYWwgcGxvdCBzaG93aW5nIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgSm91cm5hbCBDaXRhdGlvbiBSZXBvcnQgQ2F0ZWdvcnkgYW5kIHZpc3VhbGl6YXRpb24gbWV0aG9kLiANCmBgYHtyLCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9MTB9DQojIERhdGEgVHJhbnNmb3JtYXRpb24gDQp2aXN1YWxpemF0aW9uX2FsbHV2aWFsIDwtIHNkICU+JSANCiAgICBzZXBhcmF0ZV9yb3dzKHZpc3VhbGl6YXRpb25fbWV0aG9kLCBzZXAgPSAiLFxccysiKSAlPiUNCiAgICBmaWx0ZXIoIWlzLm5hKHZpc3VhbGl6YXRpb25fbWV0aG9kKSkgJT4lDQogICAgc2VwYXJhdGVfcm93cyhKb3VybmFsX0NhdGVnb3J5X0FsbG9jYXRlZF9Ccm9hZCwgc2VwID0gIi9cXHMrIikgJT4lDQogICAgZ3JvdXBfYnkoSm91cm5hbF9DYXRlZ29yeV9BbGxvY2F0ZWRfQnJvYWQsIHZpc3VhbGl6YXRpb25fbWV0aG9kKSAlPiUgDQogICAgY291bnQodmlzdWFsaXphdGlvbl9tZXRob2QsIEpvdXJuYWxfQ2F0ZWdvcnlfQWxsb2NhdGVkX0Jyb2FkKSAlPiUgDQogICAgc3VtbWFyaXNlKGZyZXEgPSBuKCksIC5ncm91cHMgPSAnZHJvcCcpICU+JSANCiAgICBncm91cF9ieSh2aXN1YWxpemF0aW9uX21ldGhvZCkgDQoNCg0KIyBDcmVhdGUgdGhlIEFsbHV2aWFsIHBsb3QNCmFsbHV2aWFsX3ZpcyA8LSB2aXN1YWxpemF0aW9uX2FsbHV2aWFsICU+JSANCmdncGxvdChhZXMoeSA9IGZyZXEgLGF4aXMxID0gSm91cm5hbF9DYXRlZ29yeV9BbGxvY2F0ZWRfQnJvYWQsIGF4aXMyID0gdmlzdWFsaXphdGlvbl9tZXRob2QpKSArDQogIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gYygiSm91cm5hbCBDaXRhdGlvbiBSZXBvcnQgQ2F0ZWdvcnkiLCAiUk9CIEFzc2Vzc21lbnQgTWV0aG9kIiksIGV4cGFuZCA9IGMoLjA1LCAuMDUpKSArDQogIHhsYWIoIlZhcmlhYmxlcyIpICsNCiAgZ2VvbV9hbGx1dml1bShhZXMoZmlsbCA9IEpvdXJuYWxfQ2F0ZWdvcnlfQWxsb2NhdGVkX0Jyb2FkKSkgKw0KICBnZW9tX3N0cmF0dW0od2lkdGggPSAxLzQsIGZpbGwgPSAid2hpdGUiLCBjb2xvciA9ICJibGFjayIpICsNCiAgZ2VvbV90ZXh0KHN0YXQgPSAic3RyYXR1bSIsIGFlcyhsYWJlbCA9IGFmdGVyX3N0YXQoc3RyYXR1bSkpLCBzaXplID0gNikgKw0KICBsYWJzKHg9ICJWYXJpYWJsZXMiLCB5ID0gIkZyZXF1ZW5jeSIsIGZpbGwgPSAiSm91cm5hbCBDYXRlZ29yeSBBbGxvY2F0ZWQiKSArDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiKSArDQogIG9yZ2Fub2NobG9yVEhFTUUoKSANCg0KYWxsdXZpYWxfdmlzDQoNCiMgZ2dzYXZlKGhlcmUoImZpZ3VyZXMiLCAiYWxsdXZpYWxfdmlzLnBkZiIpLCB3aWR0aCA9IDE2LCBoZWlnaHQgPSAxMCwgdW5pdHMgPSAiY20iLCBzY2FsZSA9IDIsIGRwaSA9IDgwMCkNCiMgZ2dzYXZlKGhlcmUoImZpZ3VyZXMiLCAiYWxsdXZpYWxfdmlzLmpwZyIpLCB3aWR0aCA9IDE2LCBoZWlnaHQgPSAxMCwgdW5pdHMgPSAiY20iLCBzY2FsZSA9IDIsIGRwaSA9IDgwMCkNCmBgYA0KDQojIyBCYXIgcGxvdCBmb3IgcmlzayBvZiBiaWFzIA0KQmFyIHBsb3Qgc2hvd2luZyB0aGUgcGVyY2VudGFnZSBhbmQgdG90YWwgY291bnQgb2YgcmlzayBvZiBiaWFzIHRlc3RzIHVzZWQgaW4gbWV0YS1hbmFseXNlcyBpbnZlc3RpZ2F0aW5nIHRoZSBpbXBhY3RzIG9mIG9yZ2Fub2NobG9yaW5lIHBlc3RpY2lkZXMuIE5vdGUgdGhhdCBzb21lIG1ldGEtYW5hbHlzZXMgbWF5IGNvbnRyaWJ1dGUgdG8gbXVsdGlwbGUgc2VjdGlvbnMgaWYgdGhlIHN0dWR5IGludm9sdmVkIHRoZSB1c2Ugb2YgbXVsdGlwbGUgcmlzayBvZiBiaWFzIHRlc3RzLiANCmBgYHtyLCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9MTB9DQojIENhbGN1bGF0ZSB0aGUgdG90YWwgY291bnQgZm9yIGVhY2ggY2F0ZWdvcnkNCnJvYl9tZXRob2RfY291bnQgPC0gc2QgJT4lIA0KICBzZXBhcmF0ZV9yb3dzKHJvYl9hc3Nlc3NtZW50X21ldGhvZCwgc2VwID0gIixcXHMrIikgJT4lIA0KICBjb3VudChyb2JfYXNzZXNzbWVudF9tZXRob2QpICU+JQ0KICBmaWx0ZXIocm9iX2Fzc2Vzc21lbnRfbWV0aG9kICE9ICJOQSIpICU+JQ0KICBtdXRhdGUocm9iX2Fzc2Vzc21lbnRfbWV0aG9kID0gaWZlbHNlKG4gPD0gMiwgIk90aGVyIFJPQiB0b29sIiwgYXMuY2hhcmFjdGVyKHJvYl9hc3Nlc3NtZW50X21ldGhvZCkpKSAlPiUgDQogIG11dGF0ZShyb2JfYXNzZXNzbWVudF9tZXRob2QgPSBpZmVsc2UoZ3JlcGwoIk5ld2Nhc3RsZSBPdHRhd2Egc2NhbGUiLCByb2JfYXNzZXNzbWVudF9tZXRob2QpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTmV3Y2FzdGxlIE90dGF3YVxuc2NhbGUiLCByb2JfYXNzZXNzbWVudF9tZXRob2QpKSAlPiUNCiAgZ3JvdXBfYnkocm9iX2Fzc2Vzc21lbnRfbWV0aG9kKSAlPiUNCiAgc3VtbWFyaXNlKG4gPSBzdW0obikpDQoNCiMgQ2FsY3VsYXRlIHByb3BvcnRpb24gYW5kIHBlcmNlbnRhZ2UgZm9yIGVhY2ggY2F0ZWdvcnkNCnJvYl9tZXRob2RfcGN0IDwtIHJvYl9tZXRob2RfY291bnQgJT4lDQogIG11dGF0ZShwcm9wb3J0aW9uID0gbiAvIDgzLA0KICAgICAgICAgcGVyY2VudGFnZSA9IHByb3BvcnRpb24gKiAxMDApDQoNCiMgQ3JlYXRlIHRoZSBjb3VudCBwbG90DQpiYXJfcmlza19vZl9iaWFzIDwtIHJvYl9tZXRob2RfY291bnQgJT4lDQogIGdncGxvdChhZXMoeCA9IG4sIHkgPSByZW9yZGVyKHJvYl9hc3Nlc3NtZW50X21ldGhvZCwgbiksIA0KICAgICAgICAgICAgIGZpbGwgPSBpZmVsc2UoZ3JlcGwoIk5vdCByZXBvcnRlZCIsIHJvYl9hc3Nlc3NtZW50X21ldGhvZCksICIjNzM3MGIzIiwgIiMxYjllNzciKSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMC44ICwgYWxwaGEgPSAwLjcpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IG4sIHggPSBuLzIsIHkgPSByZW9yZGVyKHJvYl9hc3Nlc3NtZW50X21ldGhvZCwgbikpLCANCiAgICAgICAgICAgIGhqdXN0ID0gMC41LCBzaXplID0gMTIsIGNvbG9yID0gImJsYWNrIikgKw0KICBnZW9tX3RleHQoZGF0YSA9IHJvYl9tZXRob2RfcGN0LCBhZXMobGFiZWwgPSBwYXN0ZTAoIigiLCByb3VuZChwZXJjZW50YWdlLCAwKSwgIiUpIiksIHggPSBuKSwgDQogICAgICAgICAgICBoanVzdCA9IC0wLjEsIHNpemUgPSAxMiwgY29sb3IgPSAiYmxhY2siLCBmb250ZmFjZSA9ICJib2xkIikgKw0KICBzY2FsZV9maWxsX2lkZW50aXR5KGd1aWRlID0gIm5vbmUiKSArDQogIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBjKDAsIDApLCBsaW1pdHMgPSBjKDAsIG1heChyb2JfbWV0aG9kX2NvdW50JG4pKjEuMykpICsNCiAgbGFicyh0aXRsZSA9IE5VTEwsIHggPSBOVUxMLCB5ID0gTlVMTCkgKw0KICBvcmdhbm9jaGxvclRIRU1FKCkgDQoNCmJhcl9yaXNrX29mX2JpYXMNCg0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJiYXJfcGxvdF9yaXNrX29mX2JpYXMucGRmIiksIHdpZHRoID0gMTYsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJiYXJfcGxvdF9yaXNrX29mX2JpYXMuanBnIiksIHdpZHRoID0gMTYsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KDQpgYGANCg0KIyMgQWxsdXZpYWwgcGxvdCBmb3IgcmlzayBvZiBiaWFzDQpBbGx1dmlhbCBwbG90IHNob3dpbmcgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBKb3VybmFsIENpdGF0aW9uIFJlcG9ydCBDYXRlZ29yeSBhbmQgcmlzayBvZiBiaWFzIG1ldGhvZG9sb2d5LiANCmBgYHtyLCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9MTB9DQojIERhdGEgVHJhbnNmb3JtYXRpb24gDQpyb2JtZXRob2RfYWxsdXZpYWwgPC0gc2QgJT4lIA0KICBzZXBhcmF0ZV9yb3dzKHJvYl9hc3Nlc3NtZW50X21ldGhvZCwgc2VwID0gIixcXHMrIikgJT4lDQogIGZpbHRlcighaXMubmEocm9iX2Fzc2Vzc21lbnRfbWV0aG9kKSkgJT4lDQogIHNlcGFyYXRlX3Jvd3MoSm91cm5hbF9DYXRlZ29yeV9BbGxvY2F0ZWRfQnJvYWQsIHNlcCA9ICIvXFxzKyIpICU+JQ0KICBncm91cF9ieShKb3VybmFsX0NhdGVnb3J5X0FsbG9jYXRlZF9Ccm9hZCwgcm9iX2Fzc2Vzc21lbnRfbWV0aG9kKSAlPiUgDQogIGNvdW50KHJvYl9hc3Nlc3NtZW50X21ldGhvZCwgSm91cm5hbF9DYXRlZ29yeV9BbGxvY2F0ZWRfQnJvYWQpICU+JSANCiAgc3VtbWFyaXNlKGZyZXEgPSBuKCksIC5ncm91cHMgPSAnZHJvcCcpICU+JSANCiAgZ3JvdXBfYnkocm9iX2Fzc2Vzc21lbnRfbWV0aG9kKSANCg0KIyBDcmVhdGUgdGhlIEFsbHV2aWFsIHBsb3QNCmFsbHV2aWFsX3Jpc2tfb2ZfYmlhcyA8LSByb2JtZXRob2RfYWxsdXZpYWwgJT4lIA0KICBnZ3Bsb3QoYWVzKHkgPSBmcmVxICxheGlzMSA9IEpvdXJuYWxfQ2F0ZWdvcnlfQWxsb2NhdGVkX0Jyb2FkLCBheGlzMiA9IHJvYl9hc3Nlc3NtZW50X21ldGhvZCkpICsNCiAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSBjKCJKb3VybmFsIENpdGF0aW9uIENhdGVnb3J5IiwgIlJPQiBBc3Nlc3NtZW50IE1ldGhvZCIpLCBleHBhbmQgPSBjKC4wNSwgLjA1KSkgKw0KICB4bGFiKCJWYXJpYWJsZXMiKSArDQogIGdlb21fYWxsdXZpdW0oYWVzKGZpbGwgPSBKb3VybmFsX0NhdGVnb3J5X0FsbG9jYXRlZF9Ccm9hZCkpICsNCiAgZ2VvbV9zdHJhdHVtKHdpZHRoID0gMS8zLCBmaWxsID0gIndoaXRlIiwgY29sb3IgPSAiYmxhY2siKSArDQogIGdlb21fdGV4dChzdGF0ID0gInN0cmF0dW0iLCBhZXMobGFiZWwgPSBhZnRlcl9zdGF0KHN0cmF0dW0pKSwgc2l6ZSA9IDUpICsNCiAgbGFicyh4PSAiVmFyaWFibGVzIiwgeSA9ICJGcmVxdWVuY3kiLCBmaWxsID0gIkpvdXJuYWwgQ2F0ZWdvcnkgQWxsb2NhdGVkIikgKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIikgKw0KICBvcmdhbm9jaGxvclRIRU1FKCkgDQoNCmFsbHV2aWFsX3Jpc2tfb2ZfYmlhcw0KDQojIGdnc2F2ZShoZXJlKCJmaWd1cmVzIiwgImFsbHV2aWFsX3Bsb3Rfcmlza19vZl9iaWFzLnBkZiIpLCB3aWR0aCA9IDE2LCBoZWlnaHQgPSAxMCwgdW5pdHMgPSAiY20iLCBzY2FsZSA9IDIsIGRwaSA9IDgwMCkNCiMgZ2dzYXZlKGhlcmUoImZpZ3VyZXMiLCAiYWxsdXZpYWxfcGxvdF9yaXNrX29mX2JpYXMuanBnIiksIHdpZHRoID0gMTYsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KDQpgYGANCg0KDQojIyBCYXIgcGxvdCBmb3IgYmlhcyB2aXN1YWxpemF0aW9ucw0KQmFyIHBsb3Qgc2hvd2luZyB0aGUgcGVyY2VudGFnZSBhbmQgdG90YWwgY291bnQgb2YgYmlhcyB2aXN1YWxpemF0aW9ucyB1c2VkIGluIG1ldGEtYW5hbHlzZXMgaW52ZXN0aWdhdGluZyB0aGUgaW1wYWN0cyBvZiBvcmdhbm9jaGxvcmluZSBwZXN0aWNpZGVzLiBOb3RlIHRoYXQgc29tZSBtZXRhLWFuYWx5c2VzIG1heSBjb250cmlidXRlIHRvIG11bHRpcGxlIHNlY3Rpb25zIGlmIHRoZSBzdHVkeSBpbnZvbHZlZCB0aGUgdXNlIG9mIG11bHRpcGxlIGJpYXMgdmlzdWFsaXphdGlvbnMuIA0KYGBge3IsIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD0xMH0NCiMgQ2FsY3VsYXRlIHRoZSB0b3RhbCBjb3VudCBmb3IgZWFjaCBjYXRlZ29yeQ0KYmlhc192aXN1YWxpemF0aW9uX2NvdW50IDwtIHNkICU+JSANCiAgc2VwYXJhdGVfcm93cyhiaWFzX2Fzc2Vzc21lbnRfdmlzdWFsaXphdGlvbiwgc2VwID0gIixcXHMrIikgJT4lIA0KICBjb3VudChiaWFzX2Fzc2Vzc21lbnRfdmlzdWFsaXphdGlvbikgJT4lDQogIGZpbHRlcihiaWFzX2Fzc2Vzc21lbnRfdmlzdWFsaXphdGlvbiAhPSAiTkEiKSAlPiUNCiAgZ3JvdXBfYnkoYmlhc19hc3Nlc3NtZW50X3Zpc3VhbGl6YXRpb24pICU+JQ0KICBzdW1tYXJpc2UobiA9IHN1bShuKSkNCg0KIyBDYWxjdWxhdGUgcHJvcG9ydGlvbiBhbmQgcGVyY2VudGFnZSBmb3IgZWFjaCBjYXRlZ29yeQ0KYmlhc192aXN1YWxpemF0aW9uX3BjdCA8LSBiaWFzX3Zpc3VhbGl6YXRpb25fY291bnQgJT4lDQogIG11dGF0ZShwcm9wb3J0aW9uID0gbiAvIDgzLA0KICAgICAgICAgcGVyY2VudGFnZSA9IHByb3BvcnRpb24gKiAxMDApDQoNCiMgQ3JlYXRlIHRoZSBjb3VudCBwbG90DQpiYXJfYmlhc192aXN1YWxpemF0aW9uIDwtIGJpYXNfdmlzdWFsaXphdGlvbl9jb3VudCAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gbiwgeSA9IHJlb3JkZXIoYmlhc19hc3Nlc3NtZW50X3Zpc3VhbGl6YXRpb24sIG4pLCANCiAgICAgICAgICAgICBmaWxsID0gaWZlbHNlKGdyZXBsKCJOb3QgcmVwb3J0ZWQiLCBiaWFzX2Fzc2Vzc21lbnRfdmlzdWFsaXphdGlvbiksICIjNzM3MGIzIiwgIiMxYjllNzciKSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMC44ICwgYWxwaGEgPSAwLjcpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IG4sIHggPSBuLzIsIHkgPSByZW9yZGVyKGJpYXNfYXNzZXNzbWVudF92aXN1YWxpemF0aW9uLCBuKSksIA0KICAgICAgICAgICAgaGp1c3QgPSAwLjUsIHNpemUgPSAxMiwgY29sb3IgPSAiYmxhY2siKSArDQogIGdlb21fdGV4dChkYXRhID0gYmlhc192aXN1YWxpemF0aW9uX3BjdCwgYWVzKGxhYmVsID0gcGFzdGUwKCIoIiwgcm91bmQocGVyY2VudGFnZSwgMSksICIlKSIpLCB4ID0gbiksIA0KICAgICAgICAgICAgaGp1c3QgPSAtMC4xLCBzaXplID0gMTIsIGNvbG9yID0gImJsYWNrIiwgZm9udGZhY2UgPSAiYm9sZCIpICsNCiAgc2NhbGVfZmlsbF9pZGVudGl0eShndWlkZSA9ICJub25lIikgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLCAwKSwgbGltaXRzID0gYygwLCBtYXgoYmlhc192aXN1YWxpemF0aW9uX2NvdW50JG4pKjEuMykpICsNCiAgbGFicyh0aXRsZSA9IE5VTEwsIHggPSBOVUxMLCB5ID0gTlVMTCkgKw0KICBvcmdhbm9jaGxvclRIRU1FKCkgDQoNCmJhcl9iaWFzX3Zpc3VhbGl6YXRpb24NCg0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJiYXJfcGxvdF9iaWFzX3Zpc3VhbGl6YXRpb24ucGRmIiksIHdpZHRoID0gMTYsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJiYXJfcGxvdF9iaWFzX3Zpc3VhbGl6YXRpb24uanBnIiksIHdpZHRoID0gMTYsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KYGBgDQoNCiMjIEFsbHV2aWFsIHBsb3QgZm9yIGJpYXMgdmlzdWFsaXphdGlvbiBtZXRob2QNCkFsbHV2aWFsIHBsb3Qgc2hvd2luZyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIEpvdXJuYWwgQ2l0YXRpb24gUmVwb3J0IENhdGVnb3J5IGFuZCBiaWFzIHZpc3VhbGl6YXRpb24gbWV0aG9kLg0KYGBge3IsIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD0xMH0NCiMgRGF0YSBUcmFuc2Zvcm1hdGlvbiANCmJpYXNfdml6dWFsaXNhdGlvbl9hbGx1dmlhbCA8LSBzZCAlPiUgDQogICAgc2VwYXJhdGVfcm93cyhiaWFzX2Fzc2Vzc21lbnRfdmlzdWFsaXphdGlvbiwgc2VwID0gIixcXHMrIikgJT4lDQogICAgc2VwYXJhdGVfcm93cyhKb3VybmFsX0NhdGVnb3J5X0FsbG9jYXRlZF9Ccm9hZCwgc2VwID0gIi9cXHMrIikgJT4lIA0KICAgIGZpbHRlcighaXMubmEoYmlhc19hc3Nlc3NtZW50X3Zpc3VhbGl6YXRpb24pKSAlPiUNCiAgICBncm91cF9ieShKb3VybmFsX0NhdGVnb3J5X0FsbG9jYXRlZF9Ccm9hZCwgYmlhc19hc3Nlc3NtZW50X3Zpc3VhbGl6YXRpb24pICU+JSANCiAgICBjb3VudChiaWFzX2Fzc2Vzc21lbnRfdmlzdWFsaXphdGlvbiwgSm91cm5hbF9DYXRlZ29yeV9BbGxvY2F0ZWRfQnJvYWQpICU+JSANCiAgICBzdW1tYXJpc2UoZnJlcSA9IG4oKSwgLmdyb3VwcyA9ICdkcm9wJykgJT4lIA0KICAgIGdyb3VwX2J5KGJpYXNfYXNzZXNzbWVudF92aXN1YWxpemF0aW9uKQ0KDQojIENyZWF0ZSB0aGUgQWxsdXZpYWwgcGxvdA0KYWxsdXZpYWxfYmlhc192aXN1YWxpemF0aW9uIDwtIGJpYXNfdml6dWFsaXNhdGlvbl9hbGx1dmlhbCAlPiUgDQogIGdncGxvdChhZXMoeSA9IGZyZXEsIGF4aXMxID0gSm91cm5hbF9DYXRlZ29yeV9BbGxvY2F0ZWRfQnJvYWQsIGF4aXMyID0gYmlhc19hc3Nlc3NtZW50X3Zpc3VhbGl6YXRpb24pKSArDQogIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gYygiSm91cm5hbCBDaXRhdGlvbiBDYXRlZ29yeSIsICJCaWFzIFZpenVhbGl6YXRpb24iKSwgZXhwYW5kID0gYyguMDUsIC4wNSkpICsNCiAgeGxhYigiVmFyaWFibGVzIikgKw0KICBnZW9tX2FsbHV2aXVtKGFlcyhmaWxsID0gSm91cm5hbF9DYXRlZ29yeV9BbGxvY2F0ZWRfQnJvYWQpKSArDQogIGdlb21fc3RyYXR1bSh3aWR0aCA9IDEvNCwgZmlsbCA9ICJ3aGl0ZSIsIGNvbG9yID0gImJsYWNrIikgKw0KICBnZW9tX3RleHQoc3RhdCA9ICJzdHJhdHVtIiwgYWVzKGxhYmVsID0gYWZ0ZXJfc3RhdChzdHJhdHVtKSksIHNpemUgPSA2KSArDQogIGxhYnMoeD0gIlZhcmlhYmxlcyIsIHkgPSAiRnJlcXVlbmN5IiwgZmlsbCA9ICJKb3VybmFsIENhdGVnb3J5IEFsbG9jYXRlZCIpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpICsNCiAgb3JnYW5vY2hsb3JUSEVNRSgpIA0KDQphbGx1dmlhbF9iaWFzX3Zpc3VhbGl6YXRpb24NCg0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJhbGx1dmlhbF9wbG90X2JpYXNfdmlzdWFsaXphdGlvbi5wZGYiKSwgd2lkdGggPSAxNiwgaGVpZ2h0ID0gMTAsIHVuaXRzID0gImNtIiwgc2NhbGUgPSAyLCBkcGkgPSA4MDApDQojIGdnc2F2ZShoZXJlKCJmaWd1cmVzIiwgImFsbHV2aWFsX3Bsb3RfYmlhc192aXN1YWxpemF0aW9uLmpwZyIpLCB3aWR0aCA9IDE2LCBoZWlnaHQgPSAxMCwgdW5pdHMgPSAiY20iLCBzY2FsZSA9IDIsIGRwaSA9IDgwMCkNCmBgYA0KDQoNCiMjIENpcmN1bGFyIHRyZWVtYXAgZm9yIGV4aXN0aW5nIG1ldGhvZG9sb2dpY2FsIGFwcHJvYWNoZXMNCkEgY2lyY3VsYXIgdHJlZW1hcCBzaG93aW5nIHRoZSBjb3VudHMgb2YgZWFjaCBtZXRob2RvbG9naWNhbCBpdGVtIGluIGV4aXN0aW5nIG1ldGEtYW5hbHlzaXMgaW52ZXN0aWdhdGluZyB0aGUgaW1wYWN0cyBvZiBvcmdhbm9jaGxvcmluZSBwZXN0aWNpZGVzDQpgYGB7ciwgZmlnLndpZHRoPTIxLCBmaWcuaGVpZ2h0PTE1fQ0KIyBHcm91cGluZyAiTWVkbGluZSIgYW5kICJQdWJtZWQiIHVuZGVyICJQdWJNZWQiIGFuZCBzdW1taW5nIHRoZSBjb3VudHMNCmRhdGFiYXNlX2NvdW50IDwtIGRhdGFiYXNlX2NvdW50ICU+JQ0KICBtdXRhdGUoZGF0YWJhc2Vfc2VhcmNoID0gaWZfZWxzZShkYXRhYmFzZV9zZWFyY2ggJWluJSBjKCJNZWRsaW5lIiwgIlB1Ym1lZCIpLCAiUHViTWVkIiwgZGF0YWJhc2Vfc2VhcmNoKSkgJT4lDQogIGdyb3VwX2J5KGRhdGFiYXNlX3NlYXJjaCkgJT4lDQogIHN1bW1hcmlzZShuID0gc3VtKG4pKQ0KDQojIFNwbGl0dGluZywgZ3JvdXBpbmcsIGFuZCBzdW1taW5nIGRpZmZlcmVudCBjYXRlZ29yaWVzIG9mIGVmZmVjdCBzaXplcw0KZWZmZWN0c2l6ZV9jb3VudCA8LSBzZCAlPiUgDQogIHNlcGFyYXRlX3Jvd3MoZWZmZWN0X3NpemUsIHNlcCA9ICIsXFxzKyIpICU+JSANCiAgY291bnQoZWZmZWN0X3NpemUpICU+JQ0KICBmaWx0ZXIoZWZmZWN0X3NpemUgIT0gIk5BIikgJT4lDQogIGdyb3VwX2J5KGVmZmVjdF9zaXplKSAlPiUNCiAgc3VtbWFyaXNlKG4gPSBzdW0obikpDQoNCmVmZmVjdHNpemVfY291bnQgPC0gZWZmZWN0c2l6ZV9jb3VudCAlPiUgDQogIG11dGF0ZShlZmZlY3Rfc2l6ZSA9IGlmX2Vsc2UoZWZmZWN0X3NpemUgJWluJSBjKCJCZXRhIHJlZ3Jlc3Npb24iLCAiQ29ycmVsYXRpb24gY29lZmZpY2llbnQiKSwgIkNvcnJlbGF0aW9uIiwgZWZmZWN0X3NpemUpKSAlPiUgDQogIG11dGF0ZShlZmZlY3Rfc2l6ZSA9IGlmX2Vsc2UoZWZmZWN0X3NpemUgJWluJSBjKCJPZGRzIHJhdGlvIiwgIlJlc3BvbnNlIHJhdGlvIiwgIlN0YW5kYXJkaXplZCBtZWFuIGRpZmZlcmVuY2UiLCAiTG9nIHBhcnRpdGlvbmluZyByYXRpbyIsICJMb2cgb2RkcyByYXRpbyIsICJSYXRpbyBvZiBtZWFucyIsICJMb2cgcmVzcG9uc2UgcmF0aW8iKSwgIk1lYW4gZGlmZmVyZW5jZSIsIGVmZmVjdF9zaXplKSkgJT4lIA0KICBtdXRhdGUoZWZmZWN0X3NpemUgPSBpZl9lbHNlKGVmZmVjdF9zaXplICVpbiUgYygiUmlzayByYXRpbyIpLCAiMngyIiwgZWZmZWN0X3NpemUpKSAlPiUgDQogIG11dGF0ZShlZmZlY3Rfc2l6ZSA9IGlmX2Vsc2UoZWZmZWN0X3NpemUgJWluJSBjKCJSYXcgd2VpZ2h0IiwgIkdlb21ldHJpYyBtZWFuIiwgIk1hdGVybmFsIHRyYW5zZmVyIHJhdGlvIiwgIlN0YW5kYXJkaXplZCBtb3J0YWxpdHkgcmF0ZSIsICJUcmFuc2ZlciByYXRlIiwiVHJhbnNmZXIgcmF0aW8iLCAiWi1zY29yZSIsICJMb2cgY29lZmZpY2llbnQgdmFyaWF0aW9uIHJhdGlvIiksICJPdGhlciBFUyIsIGVmZmVjdF9zaXplKSkgJT4lIA0KICBncm91cF9ieShlZmZlY3Rfc2l6ZSkgJT4lDQogIHN1bW1hcmlzZShuID0gc3VtKG4pKQ0KDQojIENhdGVnb3JpemluZyBzb2Z0d2FyZSBhcyBlaXRoZXIgIkNvZGUtYmFzZWQgc29mdHdhcmUiIG9yICJHVUkiIGFuZCBzdW1taW5nIHRoZSBjb3VudHMNCnNvZnR3YXJlX2NvdW50IDwtIHNvZnR3YXJlX2NvdW50ICU+JQ0KICBtdXRhdGUoc29mdHdhcmVfYW5hbHlzaXMgPSBpZl9lbHNlKHNvZnR3YXJlX2FuYWx5c2lzICVpbiUgYygiU3RhdGEiLCAiUiIsICJTQVMiKSwgIkNvZGUtYmFzZWQiLCBzb2Z0d2FyZV9hbmFseXNpcykpICU+JQ0KICBtdXRhdGUoc29mdHdhcmVfYW5hbHlzaXMgPSBpZl9lbHNlKHNvZnR3YXJlX2FuYWx5c2lzICVpbiUgYygiQ01BUyIsICJFeGNlbCIsICJSZXZNYW4iLCAiWExTVEFUIiksICJHVUkiLCBzb2Z0d2FyZV9hbmFseXNpcykpICU+JSANCiAgbXV0YXRlKHNvZnR3YXJlX2FuYWx5c2lzID0gaWZfZWxzZShzb2Z0d2FyZV9hbmFseXNpcyAlaW4lIGMoIk5vdCByZXBvcnRlZCIpLCAiTm8gc29mdHdhcmUgcmVwb3J0ZWQiLCBzb2Z0d2FyZV9hbmFseXNpcykpICU+JQ0KICBncm91cF9ieShzb2Z0d2FyZV9hbmFseXNpcykgJT4lDQogIHN1bW1hcmlzZShuID0gc3VtKG4pKQ0KDQojIEdyb3VwaW5nIGhldGVyb2dlbmVpdHkgYXNzZXNzbWVudCBtZXRob2RzIGFuZCBzdW1taW5nIHRoZSBjb3VudHMNCmhldGVyb2dlbmVpdHlfY291bnQgPC0gaGV0ZXJvZ2VuZWl0eV9jb3VudCAlPiUgDQogIG11dGF0ZShoZXRlcm9nZW5laXR5X2Fzc2Vzc21lbnRfbWV0aG9kID0gaWZfZWxzZShoZXRlcm9nZW5laXR5X2Fzc2Vzc21lbnRfbWV0aG9kICVpbiUgYygiVGF1IHNxdWFyZSIpLCAiSSBzcXVhcmVkIiwgaGV0ZXJvZ2VuZWl0eV9hc3Nlc3NtZW50X21ldGhvZCkpICU+JSANCiAgbXV0YXRlKGhldGVyb2dlbmVpdHlfYXNzZXNzbWVudF9tZXRob2QgPSBpZl9lbHNlKGhldGVyb2dlbmVpdHlfYXNzZXNzbWVudF9tZXRob2QgJWluJSBjKCJDaGkgc3F1YXJlIiksICJRIHN0YXRpc3RpYyIsIGhldGVyb2dlbmVpdHlfYXNzZXNzbWVudF9tZXRob2QpKSAlPiUgDQogIG11dGF0ZShoZXRlcm9nZW5laXR5X2Fzc2Vzc21lbnRfbWV0aG9kID0gaWZfZWxzZShoZXRlcm9nZW5laXR5X2Fzc2Vzc21lbnRfbWV0aG9kICVpbiUgYygiTm90IHJlcG9ydGVkIiksICJObyBoZXRlcm9nZW5laXR5IHJlcG9ydGVkIiwgaGV0ZXJvZ2VuZWl0eV9hc3Nlc3NtZW50X21ldGhvZCkpICU+JSANCiAgZ3JvdXBfYnkoaGV0ZXJvZ2VuZWl0eV9hc3Nlc3NtZW50X21ldGhvZCkgJT4lDQogIHN1bW1hcmlzZShuID0gc3VtKG4pKQ0KDQojIEdyb3VwaW5nIGJpYXMgYXNzZXNzbWVudCBtZXRob2RzIHdpdGggY291bnQgPD0gMyB1bmRlciAiT3RoZXIgQkEiIGFuZCBzdW1taW5nIHRoZSBjb3VudHMNCmJpYXNfbWV0aG9kX2NvdW50IDwtIGJpYXNfbWV0aG9kX2NvdW50ICU+JSANCiAgbXV0YXRlKGJpYXNfYXNzZXNzbWVudF9tZXRob2QgPSBpZl9lbHNlKGJpYXNfYXNzZXNzbWVudF9tZXRob2QgJWluJSBjKCJFZ2dlcidzIHJlZ3Jlc3Npb24gdGVzdCIsICJGYWlsIHNhZmUiLCAiQmVnZydzIHRlc3QiLCAiS2VuZGFsbCdzIHRhdSBzdGF0aXN0aWMiKSwiQmlhcyBzdGF0aXN0aWNhbCB0ZXN0IiwgYmlhc19hc3Nlc3NtZW50X21ldGhvZCkpICU+JSANCiAgICBtdXRhdGUoYmlhc19hc3Nlc3NtZW50X21ldGhvZCA9IGlmX2Vsc2UoYmlhc19hc3Nlc3NtZW50X21ldGhvZCAlaW4lIGMoIk5vdCByZXBvcnRlZCIpLCJObyBiaWFzIGFzc2Vzc21lbnQgcmVwb3J0ZWQiLCBiaWFzX2Fzc2Vzc21lbnRfbWV0aG9kKSkgJT4lIA0KICBncm91cF9ieShiaWFzX2Fzc2Vzc21lbnRfbWV0aG9kKSAlPiUNCiAgc3VtbWFyaXNlKG4gPSBzdW0obikpDQoNCiMgR3JvdXBpbmcgc2Vuc2l0aXZpdHkgYW5hbHlzaXMgbWV0aG9kcyBhbmQgc3VtbWluZyB0aGUgY291bnRzDQpzZW5zaXRpdml0eV9jb3VudCA8LSAgc2Vuc2l0aXZpdHlfY291bnQgJT4lICANCiAgbXV0YXRlKHNlbnNpdGl2aXR5X2FuYWx5c2lzX21ldGhvZCA9IGlmX2Vsc2Uobjw9IDgsICJPdGhlciBzZW5zaXRpdml0eSBhbmFseXNpcyIsIGFzLmNoYXJhY3RlcihzZW5zaXRpdml0eV9hbmFseXNpc19tZXRob2QpKSkgJT4lIA0KICAgbXV0YXRlKHNlbnNpdGl2aXR5X2FuYWx5c2lzX21ldGhvZCA9IGlmX2Vsc2Uoc2Vuc2l0aXZpdHlfYW5hbHlzaXNfbWV0aG9kICVpbiUgYygiTm90IHJlcG9ydGVkIiksICJObyBzZW5zaXRpdml0eSBhbmFseXNpcyByZXBvcnRlZCIsc2Vuc2l0aXZpdHlfYW5hbHlzaXNfbWV0aG9kKSkgJT4lIA0KICBncm91cF9ieShzZW5zaXRpdml0eV9hbmFseXNpc19tZXRob2QpICU+JQ0KICBzdW1tYXJpc2UobiA9IHN1bShuKSkNCg0KIyBHcm91cGluZyByaXNrIG9mIGJpYXMgYXNzZXNzbWVudCBtZXRob2RzIHdpdGggY291bnQgPD0gMyB1bmRlciAiT3RoZXIgUk9CIiBhbmQgc3VtbWluZyB0aGUgY291bnRzDQpyb2JfbWV0aG9kX2NvdW50IDwtICByb2JfbWV0aG9kX2NvdW50ICU+JSAgDQogIG11dGF0ZShyb2JfYXNzZXNzbWVudF9tZXRob2QgPSBpZl9lbHNlKG48PSAzLCAiT3RoZXIgUk9CIHRvb2wiLCBhcy5jaGFyYWN0ZXIocm9iX2Fzc2Vzc21lbnRfbWV0aG9kKSkpICU+JSANCiAgICBtdXRhdGUocm9iX2Fzc2Vzc21lbnRfbWV0aG9kID0gaWZfZWxzZShyb2JfYXNzZXNzbWVudF9tZXRob2QgJWluJSBjKCJOb3QgcmVwb3J0ZWQiKSwgIk5vIHJpc2sgb2YgYmlhcyByZXBvcnRlZCIsIHJvYl9hc3Nlc3NtZW50X21ldGhvZCkpICU+JSANCiAgZ3JvdXBfYnkocm9iX2Fzc2Vzc21lbnRfbWV0aG9kKSAlPiUNCiAgc3VtbWFyaXNlKG4gPSBzdW0obikpDQoNCiMgR3JvdXBpbmcgdmlzdWFsaXphdGlvbiBtZXRob2RzIHdpdGggY291bnQgPD0gMyB1bmRlciAiT3RoZXIgVml6IiBhbmQgc3VtbWluZyB0aGUgY291bnRzDQp2aXN1YWxpemF0aW9uX2NvdW50IDwtIHZpc3VhbGl6YXRpb25fY291bnQgJT4lIA0KICAgbXV0YXRlKHZpc3VhbGl6YXRpb25fbWV0aG9kID0gaWZfZWxzZShuPD0gMywgIk90aGVyIFZpeiIsIGFzLmNoYXJhY3Rlcih2aXN1YWxpemF0aW9uX21ldGhvZCkpKSAlPiUgDQogIG11dGF0ZSh2aXN1YWxpemF0aW9uX21ldGhvZCA9IGlmX2Vsc2UodmlzdWFsaXphdGlvbl9tZXRob2QgJWluJSBjKCJOb3QgcmVwb3J0ZWQiKSwgIk5vIHZpenVhbGl6YXRpb24gcmVwb3J0ZWQiLCB2aXN1YWxpemF0aW9uX21ldGhvZCkpICU+JSANCiAgZ3JvdXBfYnkodmlzdWFsaXphdGlvbl9tZXRob2QpICU+JQ0KICBzdW1tYXJpc2UobiA9IHN1bShuKSkNCg0KIyBHcm91cGluZyByZXBvcnRpbmcgc3RhbmRhcmRzIHR5cGVzIHdpdGggY291bnQgPD0gMiB1bmRlciAiT3RoZXIgZ3VpZGVsaW5lIiBhbmQgc3VtbWluZyB0aGUgY291bnRzDQpyZXBvcnRpbmdfZ3VpZGVfY291bnQgPC0gcmVwb3J0aW5nX2d1aWRlX2NvdW50ICU+JSANCiAgbXV0YXRlKHJlcG9ydGluZ19zdGFuZGFyZHNfdHlwZSA9IGlmZWxzZShuPD0gMiwgIk90aGVyIGd1aWRlbGluZSIsIGFzLmNoYXJhY3RlcihyZXBvcnRpbmdfc3RhbmRhcmRzX3R5cGUpKSkgJT4lIA0KICBtdXRhdGUocmVwb3J0aW5nX3N0YW5kYXJkc190eXBlID0gaWZlbHNlKHJlcG9ydGluZ19zdGFuZGFyZHNfdHlwZSAlaW4lIGMoIk5vdCByZXBvcnRlZCIpLCAiTm8gcmVwb3J0aW5nIGd1aWRlbGluZSByZXBvcnRlZCIscmVwb3J0aW5nX3N0YW5kYXJkc190eXBlKSkgJT4lIA0KICBncm91cF9ieShyZXBvcnRpbmdfc3RhbmRhcmRzX3R5cGUpICU+JQ0KICBzdW1tYXJpc2UobiA9IHN1bShuKSkNCg0KIyBHcm91cGluZyBiaWFzIGFzc2Vzc21lbnQgdmlzdWFsaXphdGlvbiB0eXBlcyBhbmQgc3VtbWluZyB0aGUgY291bnRzDQpiaWFzX3Zpc3VhbGl6YXRpb25fY291bnQgPC0gYmlhc192aXN1YWxpemF0aW9uX2NvdW50ICU+JSANCiAgbXV0YXRlKGJpYXNfYXNzZXNzbWVudF92aXN1YWxpemF0aW9uID0gaWZfZWxzZShiaWFzX2Fzc2Vzc21lbnRfdmlzdWFsaXphdGlvbiAlaW4lIGMoIkRvaSBwbG90IiwgIlRyaW0gYW5kIGZpbGwiLCAiRnVubmVsIHBsb3QiLCAiR2FsYnJhaXRoIHBsb3QiKSwgIkJpYXMgdmlzdWFsaXphdGlvbiIsIGJpYXNfYXNzZXNzbWVudF92aXN1YWxpemF0aW9uKSkgJT4lIA0KICBtdXRhdGUoYmlhc19hc3Nlc3NtZW50X3Zpc3VhbGl6YXRpb24gPSBpZl9lbHNlKGJpYXNfYXNzZXNzbWVudF92aXN1YWxpemF0aW9uICVpbiUgYygiTm90IHJlcG9ydGVkIiksICJObyBiaWFzIHZpc3VhbGl6YXRpb24gcmVwb3J0ZWQiLCBiaWFzX2Fzc2Vzc21lbnRfdmlzdWFsaXphdGlvbikpICU+JSANCiAgZ3JvdXBfYnkoYmlhc19hc3Nlc3NtZW50X3Zpc3VhbGl6YXRpb24pICU+JQ0KICBzdW1tYXJpc2UobiA9IHN1bShuKSkNCg0KIyBDb21iaW5lIHRoZSBkYXRhIGZyYW1lcyBhbmQgdW5pdGUgdGhlIG1ldGhvZG9sb2d5IHR5cGVzDQpkZiA8LSBiaW5kX3Jvd3MoDQogIGRhdGFiYXNlX2NvdW50ICU+JSBtdXRhdGUobWV0aG9kb2xvZ3lfdHlwZSA9ICdEYXRhYmFzZSBTZWFyY2gnKSwNCiAgZWZmZWN0c2l6ZV9jb3VudCAlPiUgbXV0YXRlKG1ldGhvZG9sb2d5X3R5cGUgPSAnRWZmZWN0IFNpemUnKSwNCiAgc29mdHdhcmVfY291bnQgJT4lICBtdXRhdGUobWV0aG9kb2xvZ3lfdHlwZSA9ICJTb2Z0d2FyZSIpLA0KICBoZXRlcm9nZW5laXR5X2NvdW50ICU+JSBtdXRhdGUobWV0aG9kb2xvZ3lfdHlwZSA9ICJIZXRlcm9nZW5laXR5IiksDQogIHNlbnNpdGl2aXR5X2NvdW50ICU+JSBtdXRhdGUobWV0aG9kb2xvZ3lfdHlwZSA9ICJTZW5zaXRpdml0eV9BbmFseXNpcyIpLA0KICBiaWFzX21ldGhvZF9jb3VudCAlPiUgIG11dGF0ZShtZXRob2RvbG9neV90eXBlID0gIkJpYXMgQXNzZXNzbWVudCIpLA0KICByb2JfbWV0aG9kX2NvdW50ICU+JSBtdXRhdGUobWV0aG9kb2xvZ3lfdHlwZSA9ICJSaXNrICBvZiBCaWFzIiksIA0KICMgdmlzdWFsaXphdGlvbl9jb3VudCAlPiUgbXV0YXRlKG1ldGhvZG9sb2d5X3R5cGUgPSAiVmlzdWFsaXphdGlvbiIpLA0KICByZXBvcnRpbmdfZ3VpZGVfY291bnQgJT4lICBtdXRhdGUobWV0aG9kb2xvZ3lfdHlwZSA9ICJSZXBvcnRpbmcgR3VpZGUiKSwNCiAgYmlhc192aXN1YWxpemF0aW9uX2NvdW50ICU+JSAgbXV0YXRlKG1ldGhvZG9sb2d5X3R5cGUgPSAiQmlhcyBBc3Nlc3NtZW50IikNCikgJT4lIA0KIHVuaXRlKG1ldGhvZG9sb2d5X3R5cGVfc3BlY2lmaWMsIA0KICAgICAgIGRhdGFiYXNlX3NlYXJjaCwgDQogICAgICAgZWZmZWN0X3NpemUsICANCiAgICAgICBzb2Z0d2FyZV9hbmFseXNpcywNCiAgICAgICBoZXRlcm9nZW5laXR5X2Fzc2Vzc21lbnRfbWV0aG9kLCANCiAgICAgICBzZW5zaXRpdml0eV9hbmFseXNpc19tZXRob2QsIA0KICAgICAgIGJpYXNfYXNzZXNzbWVudF9tZXRob2QsDQogICAgICAgcm9iX2Fzc2Vzc21lbnRfbWV0aG9kLCANCiAgICAgICMgdmlzdWFsaXphdGlvbl9tZXRob2QsIA0KICAgICAgIHJlcG9ydGluZ19zdGFuZGFyZHNfdHlwZSwgDQogICAgICAgYmlhc19hc3Nlc3NtZW50X3Zpc3VhbGl6YXRpb24sDQogICAgICAgcmVtb3ZlID0gVFJVRSwgbmEucm0gPSBUUlVFKQ0KDQojIFByZXBhcmluZyB0aGUgZWRnZXMgZGF0YWZyYW1lIGZvciBjcmVhdGluZyB0aGUgZ3JhcGgNCmVkZ2VzIDwtIGRmICU+JQ0KICByZW5hbWUoZnJvbSA9IG1ldGhvZG9sb2d5X3R5cGUsIHRvID0gbWV0aG9kb2xvZ3lfdHlwZV9zcGVjaWZpYywgc2l6ZSA9IG4pICU+JQ0KICBzZWxlY3QoYyhmcm9tLHRvLHNpemUpKSAlPiUNCiAgYXMuZGF0YS5mcmFtZSgpDQoNCiMgUHJlcGFyaW5nIHRoZSB2ZXJ0aWNlcyBkYXRhZnJhbWUgZm9yIGNyZWF0aW5nIHRoZSBncmFwaA0KdmVydGljZXMgPC0gZGYgICU+JQ0KICByZW5hbWUobmFtZSA9IG1ldGhvZG9sb2d5X3R5cGVfc3BlY2lmaWMsIHNpemUgPSBuKSAlPiUNCiAgc2VsZWN0KGMobmFtZSxzaXplKSkgJT4lDQogIGFzLmRhdGEuZnJhbWUoKQ0KDQojIEFwcGVuZGluZyB1bmlxdWUgJ2Zyb20nIHZhbHVlcyB0byB2ZXJ0aWNlcyBhbmQgdGhlaXIgY29ycmVzcG9uZGluZyBzdW1tZWQgc2l6ZXMNCnZlcnRpY2VzWyhucm93KGVkZ2VzKSsxKToobnJvdyhlZGdlcykrbGVuZ3RoKHVuaXF1ZShlZGdlcyRmcm9tKSkpLDFdIDwtIHVuaXF1ZShlZGdlcyRmcm9tKQ0KTiA8LSBhZ2dyZWdhdGUoZWRnZXMkc2l6ZSwgbGlzdChlZGdlcyRmcm9tKSwgRlVOPXN1bSkNCnZlcnRpY2VzWyhucm93KGVkZ2VzKSsxKToobnJvdyhlZGdlcykrbGVuZ3RoKHVuaXF1ZShlZGdlcyRmcm9tKSkpLDJdIDwtIE4keA0KDQojIENyZWF0aW5nIGEgZ3JhcGggb2JqZWN0IGZyb20gdGhlIGVkZ2VzIGFuZCB2ZXJ0aWNlcyBkYXRhZnJhbWVzDQpteWdyYXBoIDwtIGdyYXBoX2Zyb21fZGF0YV9mcmFtZShlZGdlcywgdmVydGljZXMgPSB2ZXJ0aWNlcykNCg0KIyBQbG90dGluZyB0aGUgZ3JhcGggdXNpbmcgYSAnY2lyY2xlcGFjaycgbGF5b3V0DQpjaXJjdWxhcl90cmVlbWFwX21ldGhvZHMgPC0gZ2dyYXBoKG15Z3JhcGgsIGxheW91dCA9ICdjaXJjbGVwYWNrJywgd2VpZ2h0ID0gc2l6ZSkgKyANCiAgICBnZW9tX25vZGVfY2lyY2xlKGFlcyhmaWxsID0gYXMuZmFjdG9yKGRlcHRoKSksIGNvbG9yID0gTkEpICsNCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjMWI5ZTc3IiwgIiM4OEQxQUQiKSkgKyANCiAgICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBuYW1lLCBmaWx0ZXIgPSBsZWFmLCBzaXplID0gMTApLCB2anVzdCA9IC0wLjMsIGZvbnRmYWNlID0gImJvbGQiKSArDQogICAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gcGFzdGUwKCIoIiwgc2l6ZSwgIikiKSwgZmlsdGVyID0gbGVhZiwgc2l6ZSA9IDEwKSwgdmp1c3QgPSAxLCBmb250ZmFjZSA9ICJib2xkIikgKw0KICAgIHRoZW1lX3ZvaWQoKSArDQogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSANCg0KY2lyY3VsYXJfdHJlZW1hcF9tZXRob2RzDQoNCiMgZ2dzYXZlKGhlcmUoImZpZ3VyZXMiLCAiY2lyY3VsYXJfdHJlZW1hcF9tZXRob2RzLnBkZiIpLCB3aWR0aCA9IDE4LCBoZWlnaHQgPSAxNSwgdW5pdHMgPSAiY20iLCBzY2FsZSA9IDIsIGRwaSA9IDgwMCkNCiMgZ2dzYXZlKGhlcmUoImZpZ3VyZXMiLCAiY2lyY3VsYXJfdHJlZW1hcF9tZXRob2RzLmpwZyIpLCB3aWR0aCA9IDE4LCBoZWlnaHQgPSAxNSwgdW5pdHMgPSAiY20iLCBzY2FsZSA9IDIsIGRwaSA9IDgwMCkNCmBgYA0KDQojIyBEb251dCBwbG90IGZvciBjb25mb3VuZCBhbmFseXNpcw0KRG9udXQgcGxvdCBzaG93aW5nIHRoZSBwcm9wb3J0aW9uIG9mIHN0dWRpZXMgd2hpY2ggaW5jbHVkZWQgY29uZm91bmRzICh0aHJvdWdoIHJpc2sgb2YgYmlhcyBhc3Nlc3NtZW50cykgaW4gdGhlIGFuYWx5c2lzIChncmVlbiA9IG5vdCByZXBvcnRlZCwgb3JhbmdlID0gcmVwb3J0ZWQpLg0KYGBge3J9DQojIFJlbW92ZSBOQSB2YWx1ZXMgYW5kIGNvdW50IFllcy9Obw0KY29uZm91bmRfZGF0YSA8LSBzZCAlPiUNCiAgZmlsdGVyKCFpcy5uYShjb25mb3VuZF9hbmFseXNpcykpICU+JQ0KICBjb3VudChjb25mb3VuZF9hbmFseXNpcykgJT4lDQogIG11dGF0ZShwZXJjZW50YWdlID0gbiAvIHN1bShuKSAqIDEwMCkNCg0KIyBEb251dCBQbG90IHdpdGggYSBob2xlDQpkb251dF9wbG90IDwtIGdncGxvdChjb25mb3VuZF9kYXRhLCBhZXMoeCA9IDIsIHkgPSBwZXJjZW50YWdlLCBmaWxsID0gY29uZm91bmRfYW5hbHlzaXMpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDEsIGNvbG9yID0gIndoaXRlIikgKw0KICBjb29yZF9wb2xhcih0aGV0YSA9ICJ5Iiwgc3RhcnQgPSAwKSArDQogIGdlb21fdGV4dCgNCiAgICBhZXMobGFiZWwgPSBwYXN0ZTAocm91bmQocGVyY2VudGFnZSwgMSksICIlIikpLCANCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSwgDQogICAgc2l6ZSA9IDUsIA0KICAgIGZvbnRmYWNlID0gImJvbGQiLA0KICAgIGNvbG9yID0gIndoaXRlIg0KICApICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygieWVzIiA9ICIjZDk1ZjAyIiwgIm5vIiA9ICIjMWI5ZTc3IikpICsgICMgQ3VzdG9tIGNvbG9ycw0KICBsYWJzKGZpbGwgPSBOVUxMKSArICAjIFJlbW92ZSBsZWdlbmQgdGl0bGUNCiAgdGhlbWVfdm9pZCgpICsNCiAgdGhlbWUoDQogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCAgIyBSZW1vdmUgbGVnZW5kDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsIGZhY2UgPSAiYm9sZCIsIGhqdXN0ID0gMC41KQ0KICApICsNCiAgeGxpbSgwLjUsIDIuNSkgICMgQ3JlYXRlcyB0aGUgaG9sZSBpbiB0aGUgbWlkZGxlDQoNCiMgU2F2ZSBmaWd1cmVzDQojIGdnc2F2ZShoZXJlKCJmaWd1cmVzIiwgImRvbnV0X2NvbmZvdW5kLnBkZiIpLCBwbG90ID0gZG9udXRfcGxvdCwgd2lkdGggPSA4LCBoZWlnaHQgPSA4LCB1bml0cyA9ICJjbSIsIGRwaSA9IDgwMCkNCiMgZ2dzYXZlKGhlcmUoImZpZ3VyZXMiLCAiZG9udXRfY29uZm91bmQuanBnIiksIHBsb3QgPSBkb251dF9wbG90LCB3aWR0aCA9IDgsIGhlaWdodCA9IDgsIHVuaXRzID0gImNtIiwgZHBpID0gODAwKQ0KDQpgYGANCg0KDQojIFNlY3Rpb24gMiANClRvIGV4cGxvcmUgdGhlIHZhcmlvdXMgY2hhcmFjdGVyaXN0aWNzIG9mIHRoZSBvcmdhbm9jaGxvcmluZSBwZXN0aWNpZGVzIGxpdGVyYXR1cmUgc3VjaCBhcyB0aGUgcGVzdGljaWRlcyB1c2VkLCB0aGUgaW1wYWN0cyBlbGljaXRlZCBpbiByZXNwb25zZSBhbmQgdGhlIHN1YmplY3RzIHRoYXQgd2VyZSBpbnZlc3RpZ2F0ZWQuDQoNCiMjIEJhciBwbG90IGZvciBvcmdhbm9jaGxvcmluZSBwZXN0aWNpZGVzIGludmVzdGlnYXRlZA0KDQpBIGJhciBwbG90IHNob3dpbmcgdGhlIHBlcmNlbnRhZ2UgYW5kIHRvdGFsIGNvdW50IG9mIHRvdGFsIG9mIHBlc3RpY2lkZXMgaW52ZXN0aWdhdGUgaW4gbWV0YS1hbmFseXNpcyBpbnZlc3RpZ2F0aW5nIHRoZSBpbXBhY3RzIG9mIG9yZ2Fub2NobG9yaW5lIHBlc3RpY2lkZXMuIE5vdGU6IHNvbWUgbWV0YS1hbmFseXNpcyBtYXkgY29udHJpYnV0ZSB0byBtdWx0aXBsZSBzZWN0aW9ucyBpZiB0aGUgc3R1ZHkgaW52b2x2ZXMgbXVsdGlwbGUgb3JnYW5vY2hsb3JpbmUgcGVzdGljaWRlcy4gRmlsdGVyZWQgZm9yIHBlc3RpY2lkZSBjb3VudHMgZ3JlYXRlciB0aGFuIDYuIA0KYGBge3IsZmlnLndpZHRoPTE2LCBmaWcuaGVpZ2h0PTEwfQ0KIyBGdW5jdGlvbiB0byByZXBsYWNlIGxvbmcgT0NQIG5hbWVzIHdpdGggYWJicmV2aWF0aW9ucw0KcmVwbGFjZV9vY3AgPC0gZnVuY3Rpb24oZGYpIHsNCiAgZGYgJT4lIA0KICAgIG11dGF0ZShvY3AgPSBjYXNlX3doZW4oDQogICAgICAjIEhDSCByZWxhdGVkIHJlcGxhY2VtZW50cw0KICAgICAgZ3JlcGwoIkhleGFjaGxvcm9jeWNsb2hleGFuZSBcXChIQ0hcXCkiLCBvY3AsIGlnbm9yZS5jYXNlID0gVFJVRSkgfiAiSENIIiwNCiAgICAgIGdyZXBsKCJhbHBoYS1IZXhhY2hsb3JvY3ljbG9oZXhhbmUgXFwoYWxwaGEtSENIXFwpIiwgb2NwLCBpZ25vcmUuY2FzZSA9IFRSVUUpIH4gIs6xIC0gSENIIiwNCiAgICAgIGdyZXBsKCJiZXRhLUhleGFjaGxvcm9jeWNsb2hleGFuZSBcXChiZXRhLUhDSFxcKSIsIG9jcCwgaWdub3JlLmNhc2UgPSBUUlVFKSB+ICLOsiAtIEhDSCIsDQogICAgICBncmVwbCgiZ2FtbWEtSGV4YWNobG9yb2N5Y2xvaGV4YW5lIFxcKGdhbW1hLUhDSFxcKSIsIG9jcCwgaWdub3JlLmNhc2UgPSBUUlVFKSB+ICJMaW5kYW5lIiwNCiAgICAgICMgRERUIHJlbGF0ZWQgcmVwbGFjZW1lbnRzDQogICAgICBncmVwbCgiRGljaGxvcm9kaXBoZW55bHRyaWNobG9yb2V0aGFuZSBcXChERFRcXCkiLCBvY3AsIGlnbm9yZS5jYXNlID0gVFJVRSkgfiAiRERUIiwNCiAgICAgIGdyZXBsKCJwLHAtRGljaGxvcm9kaXBoZW55bHRyaWNobG9yb2V0aGFuZSBcXChwLHAtRERUXFwpIiwgb2NwLCBpZ25vcmUuY2FzZSA9IFRSVUUpIH4gInAscC1ERFQiLA0KICAgICAgZ3JlcGwoIm8scC1EaWNobG9yb2RpcGhlbnlsdHJpY2hsb3JvZXRoYW5lIFxcKG8scC1ERFRcXCkiLCBvY3AsIGlnbm9yZS5jYXNlID0gVFJVRSkgfiAibyxwLUREVCIsDQogICAgICAjIERERCByZWxhdGVkIHJlcGxhY2VtZW50cw0KICAgICAgZ3JlcGwoIkRpY2hsb3JvZGlwaGVueWxkaWNobG9yb2V0aGFuZSBcXChERERcXCkiLCBvY3AsIGlnbm9yZS5jYXNlID0gVFJVRSkgfiAiREREIiwNCiAgICAgIGdyZXBsKCJwLHAtRGljaGxvcm9kaXBoZW55bGRpY2hsb3JvZXRoYW5lIFxcKHAscC1ERERcXCkiLCBvY3AsIGlnbm9yZS5jYXNlID0gVFJVRSkgfiAicCxwLURERCIsDQogICAgICBncmVwbCgibyxwLURpY2hsb3JvZGlwaGVueWxkaWNobG9yb2V0aGFuZSBcXChvLHAtREREXFwpIiwgb2NwLCBpZ25vcmUuY2FzZSA9IFRSVUUpIH4gIm8scC1EREQiLA0KICAgICAgIyBEREUgcmVsYXRlZCByZXBsYWNlbWVudHMNCiAgICAgIGdyZXBsKCJEaWNobG9yb2RpcGhlbnlsZGljaGxvcm9ldGh5bGVuZSBcXChEREVcXCkiLCBvY3AsIGlnbm9yZS5jYXNlID0gVFJVRSkgfiAiRERFIiwNCiAgICAgIGdyZXBsKCJwLHAtRGljaGxvcm9kaXBoZW55bGRpY2hsb3JvZXRoeWxlbmUgXFwocCxwLURERVxcKSIsIG9jcCwgaWdub3JlLmNhc2UgPSBUUlVFKSB+ICJwLHAtRERFIiwNCiAgICAgIGdyZXBsKCJvLHAtRGljaGxvcm9kaXBoZW55bGRpY2hsb3JvZXRoeWxlbmUgXFwobyxwLURERVxcKSIsIG9jcCwgaWdub3JlLmNhc2UgPSBUUlVFKSB+ICJvLHAtRERFIiwNCiAgICAgIFRSVUUgfiBvY3AgICMgbm8gY2hhbmdlIGZvciBhbnkgb3RoZXJzDQogICAgKSkNCn0NCg0KIyBUcmFuc2Zvcm0gdGhlIGRhdGEgDQpvY3BfY291bnQgPC0gb2NwICU+JSANCiAgc2VwYXJhdGVfcm93cyhvY3AsIHNlcCA9ICIsXFxzKyIpICU+JSANCiAgcmVwbGFjZV9vY3AoKSAlPiUgDQogIGNvdW50KG9jcCkgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKG9jcCkpICU+JSAgIyBmaWx0ZXIgb3V0IE5BIA0KICBhcnJhbmdlKGRlc2MobikpICU+JSANCiAgbXV0YXRlKG9jcCA9IGlmZWxzZShuIDw9IDYsICJvdGhlciBPQ1AiLCBhcy5jaGFyYWN0ZXIob2NwKSkpICU+JSANCiAgZ3JvdXBfYnkob2NwKSAlPiUgDQogIHN1bW1hcmlzZShuID0gc3VtKG4pKQ0KDQojIENhbGN1bGF0ZSB0aGUgcHJvcG9ydGlvbiBhbmQgcGVyY2VudGFnZSBvZiBlYWNoIE9DUA0Kb2NwX3BjdCA8LSBvY3BfY291bnQgJT4lDQogIG11dGF0ZShwcm9wb3J0aW9uID0gbiAvIDEwNCwNCiAgICAgICAgIHBlcmNlbnRhZ2UgPSBwcm9wb3J0aW9uICogMTAwKQ0KDQojIENyZWF0ZSB0aGUgY291bnQgcGxvdCBmb3IgT0NQcw0KYmFyX3Bsb3Rfb2NwIDwtIG9jcF9jb3VudCAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gbiwgeSA9IHJlb3JkZXIob2NwLCBuKSwgZmlsbCA9ICIjMWI5ZTc3IikpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMC44LCBhbHBoYSA9IDAuNykgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gbiwgeCA9IG4gLyAyLCB5ID0gcmVvcmRlcihvY3AsIG4pKSwNCiAgICAgICAgICAgIGhqdXN0ID0gMC41LCBzaXplID0gNywgY29sb3IgPSAiYmxhY2siKSArDQogIGdlb21fdGV4dChkYXRhID0gb2NwX3BjdCwNCiAgICAgICAgICAgIGFlcyhsYWJlbCA9IHBhc3RlMCgiKCIsIHJvdW5kKHBlcmNlbnRhZ2UsIDEpLCAiJSkiKSwgeCA9IG4pLA0KICAgICAgICAgICAgaGp1c3QgPSAtMC4xLCBzaXplID0gNywgY29sb3IgPSAiYmxhY2siLCBmb250ZmFjZSA9ICJib2xkIikgKw0KICBzY2FsZV9maWxsX2lkZW50aXR5KGd1aWRlID0gIm5vbmUiKSArDQogIHNjYWxlX3hfY29udGludW91cyhuYW1lID0gIkFydGljbGUgQ291bnQiLCBleHBhbmQgPSBjKDAsIDApLCBsaW1pdHMgPSBjKDAsIG1heChvY3BfY291bnQkbikqMS4yKSkgKw0KICBsYWJzKHRpdGxlID0gTlVMTCwgeCA9IE5VTEwsIHkgPSBOVUxMKSArDQogIG9yZ2Fub2NobG9yVEhFTUUoKSArDQogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCkpICANCg0KYmFyX3Bsb3Rfb2NwDQoNCiMgZ2dzYXZlKGhlcmUoImZpZ3VyZXMiLCAiYmFyX3Bsb3RfcGVzdGljaWRlX2ludmVzdGlnYXRpb24ucGRmIiksIA0KIyAgICAgICAgcGxvdCA9IGJhcl9wbG90X29jcCwgd2lkdGggPSAyNSwgaGVpZ2h0ID0gMTUsIHVuaXRzID0gImNtIiwgc2NhbGUgPSAyLCBkcGkgPSA4MDApDQojIGdnc2F2ZShoZXJlKCJmaWd1cmVzIiwgImJhcl9wbG90X3Blc3RpY2lkZV9pbnZlc3RpZ2F0aW9uLmpwZyIpLCANCiMgICAgICAgIHBsb3QgPSBiYXJfcGxvdF9vY3AsIHdpZHRoID0gMjUsIGhlaWdodCA9IDE1LCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KDQpgYGANCg0KIyMgQmFyIHBsb3QgZm9yIHN1YmplY3RzIGludmVzdGlnYXRlZA0KQSBiYXIgcGxvdCBzaG93aW5nIHRoZSBwZXJjZW50YWdlIGFuZCB0b3RhbCBjb3VudCBvZiB0b3RhbCBvZiBzdWJqZWN0cyBpbnZlc3RpZ2F0ZSBpbiBtZXRhLWFuYWx5c2lzIGludmVzdGlnYXRpbmcgdGhlIGltcGFjdHMgb2Ygb3JnYW5vY2hsb3JpbmUgcGVzdGljaWRlcy4gTm90ZTogc29tZSBtZXRhLWFuYWx5c2lzIG1heSBjb250cmlidXRlIHRvIG11bHRpcGxlIHNlY3Rpb25zIGlmIHRoZSBzdHVkeSBpbnZvbHZlcyBtdWx0aXBsZSBzdWJqZWN0cw0KYGBge3IsZmlnLndpZHRoPTE2LCBmaWcuaGVpZ2h0PTEwfQ0KIyBDYWxjdWxhdGUgdG90YWwgY291bnQgZm9yIGVhY2ggY2F0ZWdvcnkNCnN1YmplY3RfY291bnQgPC0gc3ViICU+JSANCiAgc2VwYXJhdGVfcm93cyhzdWJqZWN0LCBzZXAgPSAiLFxccysiKSAlPiUgDQogIG11dGF0ZShzdWJqZWN0ID0gaWZlbHNlKGdyZXBsKCJOb24taHVtYW4gYW5pbWFsIiwgc3ViamVjdCwgaWdub3JlLmNhc2UgPSBUUlVFKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vbi1odW1hblxuYW5pbWFsIiwgc3ViamVjdCkpICU+JSANCiAgY291bnQoc3ViamVjdCkNCg0KIyBDYWxjdWxhdGUgcHJvcG9ydGlvbiBhbmQgcGVyY2VudGFnZSBmb3IgZWFjaCBjYXRlZ29yeQ0Kc3ViamVjdF9wY3QgPC0gc3ViamVjdF9jb3VudCAlPiUNCiAgbXV0YXRlKHByb3BvcnRpb24gPSBuIC8gMTA1LA0KICAgICAgICAgcGVyY2VudGFnZSA9IHByb3BvcnRpb24gKiAxMDApDQoNCiMgQ3JlYXRlIHRoZSBjb3VudCBwbG90IGZvciBzdWJqZWN0cw0KYmFyX3Bsb3Rfc3ViamVjdCA8LSBzdWJqZWN0X2NvdW50ICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBuLCB5ID0gcmVvcmRlcihzdWJqZWN0LCBuKSwgZmlsbCA9ICIjMWI5ZTc3IikpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMC44ICwgYWxwaGEgPSAwLjcpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IG4sIHggPSBuIC8gMiwgeSA9IHJlb3JkZXIoc3ViamVjdCwgbikpLCANCiAgICAgICAgICAgIGhqdXN0ID0gMC41LCBzaXplID0gMTIsIGNvbG9yID0gImJsYWNrIikgKw0KICBnZW9tX3RleHQoZGF0YSA9IHN1YmplY3RfcGN0LCANCiAgICAgICAgICAgIGFlcyhsYWJlbCA9IHBhc3RlMCgiKCIsIHJvdW5kKHBlcmNlbnRhZ2UsIDEpLCAiJSkiKSwgeCA9IG4pLA0KICAgICAgICAgICAgaGp1c3QgPSAtMC4xLCBzaXplID0gMTIsIGNvbG9yID0gImJsYWNrIiwgZm9udGZhY2UgPSAiYm9sZCIpICsNCiAgc2NhbGVfZmlsbF9pZGVudGl0eShndWlkZSA9ICJub25lIikgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMobmFtZSA9ICJBcnRpY2xlIENvdW50IiwgZXhwYW5kID0gYygwLCAwKSwgbGltaXRzID0gYygwLCBtYXgoc3ViamVjdF9jb3VudCRuKSoxLjIpKSArDQogIGxhYnModGl0bGUgPSBOVUxMLCB4ID0gTlVMTCwgeSA9IE5VTEwpICsNCiAgb3JnYW5vY2hsb3JUSEVNRSgpDQoNCmJhcl9wbG90X3N1YmplY3QNCg0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJiYXJfcGxvdF9zdWJqZWN0X2ludmVzdGlnYXRpb24ucGRmIiksIA0KIyAgICAgICAgcGxvdCA9IGJhcl9wbG90X3N1YmplY3QsIHdpZHRoID0gMjUsIGhlaWdodCA9IDE1LCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJiYXJfcGxvdF9zdWJqZWN0X2ludmVzdGlnYXRpb24uanBnIiksIA0KIyAgICAgICAgcGxvdCA9IGJhcl9wbG90X3N1YmplY3QsIHdpZHRoID0gMjUsIGhlaWdodCA9IDE1LCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KDQpgYGANCg0KIyMgQmFyIHBsb3QgZm9yIGltcGFjdHMgaW52ZXN0aWdhdGVkIChmaWx0ZXJlZCkNCkEgYmFyIHBsb3Qgc2hvd2luZyB0aGUgcGVyY2VudGFnZSBhbmQgdG90YWwgY291bnQgb2YgdG90YWwgb2Ygc3ViamVjdHMgaW52ZXN0aWdhdGUgaW4gbWV0YS1hbmFseXNpcyBpbnZlc3RpZ2F0aW5nIHRoZSBpbXBhY3RzIG9mIG9yZ2Fub2NobG9yaW5lIHBlc3RpY2lkZXMuIE5vdGU6IHNvbWUgbWV0YS1hbmFseXNpcyBtYXkgY29udHJpYnV0ZSB0byBtdWx0aXBsZSBzZWN0aW9ucyBpZiB0aGUgc3R1ZHkgaW52b2x2ZXMgbXVsdGlwbGUgc3ViamVjdHMuIEZpbHRlcmVkIGZvciBpbXBhY3QgY291bnRzIGdyZWF0ZXIgdGhhbiAxLiANCmBgYHtyLGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD0xMH0NCiMgQ2FsY3VsYXRlIHRvdGFsIGNvdW50IGZvciBlYWNoIGNhdGVnb3J5DQppbXBhY3RfY291bnQgPC0gaW0gJT4lIA0KICBzZXBhcmF0ZV9yb3dzKGltcGFjdCwgc2VwID0gIixcXHMrIikgJT4lIA0KICBjb3VudChpbXBhY3QpICU+JSANCiAgZmlsdGVyKGltcGFjdCAhPSAiTkEiKSAlPiUgDQogIG11dGF0ZShpbXBhY3QgPSBpZmVsc2UobiA8PSAyLCAib3RoZXIiLCBhcy5jaGFyYWN0ZXIoaW1wYWN0KSkpICU+JSANCiAgZ3JvdXBfYnkoaW1wYWN0KSAlPiUNCiAgc3VtbWFyaXNlKG4gPSBzdW0obikpDQoNCiMgQ2FsY3VsYXRlIHByb3BvcnRpb24gYW5kIHBlcmNlbnRhZ2UgZm9yIGVhY2ggY2F0ZWdvcnkNCmltcGFjdF9wY3QgPC0gaW1wYWN0X2NvdW50ICU+JQ0KICBtdXRhdGUocHJvcG9ydGlvbiA9IG4gLyBzdW0oaW1wYWN0X2NvdW50JG4pLA0KICAgICAgICAgcGVyY2VudGFnZSA9IHByb3BvcnRpb24gKiAxMDApDQoNCiMgQ3JlYXRlIHRoZSBjb3VudCBwbG90IGZvciBpbXBhY3RzIA0KYmFyX3Bsb3RfaW1wYWN0X2ZpbHRlcmVkIDwtIGltcGFjdF9jb3VudCAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gbiwgeSA9IHJlb3JkZXIoaW1wYWN0LCBuKSwgZmlsbCA9ICIjMWI5ZTc3IikpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMC44ICwgYWxwaGEgPSAwLjcpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IG4sIHggPSBuIC8gMiwgeSA9IHJlb3JkZXIoaW1wYWN0LCBuKSksDQogICAgICAgICAgICBoanVzdCA9IDAuNSwgc2l6ZSA9IDEwLCBjb2xvciA9ICJibGFjayIpICsNCiAgZ2VvbV90ZXh0KGRhdGEgPSBpbXBhY3RfcGN0LA0KICAgICAgICAgICAgYWVzKGxhYmVsID0gcGFzdGUwKCIoIiwgcm91bmQocGVyY2VudGFnZSwgMSksICIlKSIpLCB4ID0gbiksDQogICAgICAgICAgICBoanVzdCA9IC0wLjEsIHNpemUgPSAxMCwgY29sb3IgPSAiYmxhY2siLCBmb250ZmFjZSA9ICJib2xkIikgKw0KICBzY2FsZV9maWxsX2lkZW50aXR5KGd1aWRlID0gIm5vbmUiKSArDQogIHNjYWxlX3hfY29udGludW91cyhuYW1lID0gIkFydGljbGUgQ291bnQiLCBleHBhbmQgPSBjKDAsIDApLCBsaW1pdHMgPSBjKDAsIG1heChpbXBhY3RfY291bnQkbikqMS4zKSkgKw0KICBsYWJzKHRpdGxlID0gTlVMTCwgeCA9IE5VTEwsIHkgPSBOVUxMKSArDQogIG9yZ2Fub2NobG9yVEhFTUUoKQ0KDQpiYXJfcGxvdF9pbXBhY3RfZmlsdGVyZWQNCg0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJiYXJfcGxvdF9pbXBhY3RfaW52ZXN0aWdhdGVkX2ZpbHRlcmVkLnBkZiIpLA0KIyAgICAgICAgcGxvdCA9IGJhcl9wbG90X2ltcGFjdF9maWx0ZXJlZCwgd2lkdGggPSAyNSwgaGVpZ2h0ID0gMTUsIHVuaXRzID0gImNtIiwgc2NhbGUgPSAyLCBkcGkgPSA4MDApDQojIGdnc2F2ZShoZXJlKCJmaWd1cmVzIiwgImJhcl9wbG90X2ltcGFjdF9pbnZlc3RpZ2F0ZWRfZmlsdGVyZWQuanBnIiksDQojICAgICAgICBwbG90ID0gYmFyX3Bsb3RfaW1wYWN0X2ZpbHRlcmVkLCB3aWR0aCA9IDI1LCBoZWlnaHQgPSAxNSwgdW5pdHMgPSAiY20iLCBzY2FsZSA9IDIsIGRwaSA9IDgwMCkNCg0KDQpgYGANCg0KIyMgQmFyIHBsb3QgZm9yIGJyb2FkIGltcGFjdCBjYXRlZ29yaWVzDQoNCkEgYmFyIHBsb3Qgc2hvd2luZyB0aGUgcGVyY2VudGFnZSBhbmQgdG90YWwgY291bnQgb2YgdG90YWwgb2YgaW1wYWN0IGNhdGVnb3JpZXMgaW52ZXN0aWdhdGVkIGluIG1ldGEtYW5hbHlzaXMgaW52ZXN0aWdhdGluZyB0aGUgaW1wYWN0cyBvZiBvcmdhbm9jaGxvcmluZSBwZXN0aWNpZGVzLiANCk5vdGU6IHNvbWUgbWV0YS1hbmFseXNpcyBtYXkgY29udHJpYnV0ZSB0byBtdWx0aXBsZSBzZWN0aW9ucyBpZiB0aGUgc3R1ZHkgaW52b2x2ZXMgbXVsdGlwbGUgaW1wYWN0cw0KYGBge3IsZmlnLndpZHRoPTE2LCBmaWcuaGVpZ2h0PTEwfQ0KIyBDcmVhdGUgYSBjb2x1bW4gZm9yIGJyb2FkIGltcGFjdHMNCmltIDwtIGltICU+JQ0KICBzZXBhcmF0ZV9yb3dzKGltcGFjdCwgc2VwID0gIixcXHMrIikgJT4lIA0KICBtdXRhdGUoaW1wYWN0X2Jyb2FkID0gY2FzZV93aGVuKA0KICAgIGltcGFjdCAlaW4lIGMoInBhcmtpbnNvbnMgZGlzZWFzZSIsICJhbHpoZWltZXJzIGRpc2Vhc2UiLCAiYXV0aXNtIHNwZWN0cnVtIGRpc29yZGVyIiwgDQogICAgICAgICAgICAgICAgICAiYnJhaW4gdHVtb3VyIiwgImFteW90cm9waGljIGxhdGVyYWwgc2NsZXJvc2lzIikgfiAiTmV1cm9sb2dpY2FsIiwNCiAgICBpbXBhY3QgJWluJSBjKCJjb25jZW50cmF0aW9uIiwgImNvbnRhbWluYXRpb24iKSB+ICJDb25jZW50cmF0aW9uIiwNCiAgICBpbXBhY3QgJWluJSBjKCJkaWFiZXRlcyIsICJ0aHlyb2lkIGZ1bmN0aW9uIiwgImh5cGVydGVuc2lvbiIsICJlbmRvbWV0cmlvc2lzIikgfiAiRW5kb2NyaW5lIiwNCiAgICBncmVwbCgiY2FuY2VyIiwgaW1wYWN0LCBpZ25vcmUuY2FzZSA9IFRSVUUpIHwNCiAgICAgIGltcGFjdCAlaW4lIGMoImxldWtlbWlhIiwgImx5bXBob21hIiwgIm11bHRpcGxlIG15ZWxvbWEiLCAibmV1cm9ibGFzdG9tYSIpIH4gIkNhcmNpbm9nZW4iLA0KICAgIGltcGFjdCAlaW4lIGMoInJlc3BpcmF0b3J5IGhlYWx0aCIsICJjYXJkaW92YXNjdWxhciBkaXNlYXNlIiwgImFzdGhtYSIsICJwcm9sb25nZWQgYnJhZHljYXJkaWEiKSB+ICJDYXJkaW92YXNjdWxhciIsDQogICAgaW1wYWN0ICVpbiUgYygib2Jlc2l0eSIsICJhZGlwb3NpdHkiKSB+ICJPYmVzaXR5IiwNCiAgICBpbXBhY3QgJWluJSBjKCJzcGVybSBxdWFsaXR5IiwgIm5ldXJvYmxhc3RvbWEiLCAiaHlwb3NwYWRpYXMiLCAiY3J5cHRvY2hpZGlzbSIsIA0KICAgICAgICAgICAgICAgICAgInJlcHJvZHVjdGl2ZSBzeXN0ZW0iKSB+ICJSZXByb2R1Y3Rpb24iLA0KICAgIFRSVUUgfiAiT3RoZXIgSW1wYWN0Ig0KICApKQ0KDQojIENhbGN1bGF0ZSB0b3RhbCBjb3VudCBmb3IgZWFjaCBjYXRlZ29yeQ0KaW1wYWN0X2NvdW50X2Jyb2FkIDwtIGltICU+JSANCiAgc2VwYXJhdGVfcm93cyhpbXBhY3RfYnJvYWQsIHNlcCA9ICIsXFxzKyIpICU+JSANCiAgY291bnQoaW1wYWN0X2Jyb2FkKSAlPiUgDQogIGZpbHRlcihpbXBhY3RfYnJvYWQgIT0gIk5BIikgJT4lIA0KICBncm91cF9ieShpbXBhY3RfYnJvYWQpICU+JSANCiAgc3VtbWFyaXNlKG4gPSBzdW0obikpDQoNCiMgQ2FsY3VsYXRlIHByb3BvcnRpb24gYW5kIHBlcmNlbnRhZ2UgZm9yIGVhY2ggY2F0ZWdvcnkNCmltcGFjdF9wY3RfYnJvYWQgPC0gaW1wYWN0X2NvdW50X2Jyb2FkICU+JQ0KICBtdXRhdGUocHJvcG9ydGlvbiA9IG4gLyAxMDUsDQogICAgICAgICBwZXJjZW50YWdlID0gcHJvcG9ydGlvbiAqIDEwMCkNCg0KIyBDcmVhdGUgdGhlIGNvdW50IHBsb3QgZm9yIGltcGFjdHMgDQpiYXJfcGxvdF9pbXBhY3RfYnJvYWQgPC0gaW1wYWN0X2NvdW50X2Jyb2FkICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBuLCB5ID0gcmVvcmRlcihpbXBhY3RfYnJvYWQsIG4pLCBmaWxsID0gIiMxYjllNzciKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAwLjggLCBhbHBoYSA9IDAuNykgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gbiwgeCA9IG4gLyAyLCB5ID0gcmVvcmRlcihpbXBhY3RfYnJvYWQsIG4pKSwNCiAgICAgICAgICAgIGhqdXN0ID0gMC41LCBzaXplID0gMTAsIGNvbG9yID0gImJsYWNrIikgKw0KICBnZW9tX3RleHQoZGF0YSA9IGltcGFjdF9wY3RfYnJvYWQsDQogICAgICAgICAgICBhZXMobGFiZWwgPSBwYXN0ZTAoIigiLCByb3VuZChwZXJjZW50YWdlLCAxKSwgIiUpIiksIHggPSBuKSwNCiAgICAgICAgICAgIGhqdXN0ID0gLTAuMSwgc2l6ZSA9IDEwLCBjb2xvciA9ICJibGFjayIsIGZvbnRmYWNlID0gImJvbGQiKSArDQogIHNjYWxlX2ZpbGxfaWRlbnRpdHkoZ3VpZGUgPSAibm9uZSIpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKG5hbWUgPSAiQXJ0aWNsZSBDb3VudCIsIGV4cGFuZCA9IGMoMCwgMCksIGxpbWl0cyA9IGMoMCwgbWF4KGltcGFjdF9jb3VudF9icm9hZCRuKSoxLjMpKSArDQogIGxhYnModGl0bGUgPSBOVUxMLCB4ID0gTlVMTCwgeSA9IE5VTEwpICsNCiAgb3JnYW5vY2hsb3JUSEVNRSgpDQoNCmJhcl9wbG90X2ltcGFjdF9icm9hZA0KDQojIGdnc2F2ZShoZXJlKCJmaWd1cmVzIiwgImJhcl9wbG90X2Jyb2FkX2ltcGFjdF9jYXRlZ29yeS5wZGYiKSwNCiMgICAgICAgIHBsb3QgPSBiYXJfcGxvdF9pbXBhY3RfYnJvYWQsIHdpZHRoID0gMjUsIGhlaWdodCA9IDE1LCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJiYXJfcGxvdF9icm9hZF9pbXBhY3RfY2F0ZWdvcnkuanBnIiksDQojICAgICAgICBwbG90ID0gYmFyX3Bsb3RfaW1wYWN0X2Jyb2FkLCB3aWR0aCA9IDI1LCBoZWlnaHQgPSAxNSwgdW5pdHMgPSAiY20iLCBzY2FsZSA9IDIsIGRwaSA9IDgwMCkNCg0KDQpgYGANCg0KIyMgQWxsdXZpYWwgcGxvdDogcGVzdGljaWRlIGV4cG9zdXJlLCBzdWJqZWN0LCBhbmQgaW1wYWN0DQoNCkFuIGFsbHV2aWFsIHBsb3Qgc2hvd2luZyB0aGUgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIHRoZSBwZXN0aWNpZGUgb2YgZXhwb3N1cmUsIHRoZSBzdWJqZWN0IGJlaW5nIGV4cG9zZWQgYW5kIHRoZSBpbXBhY3Qgb2YgZXhwb3N1cmUgDQpgYGB7cixmaWcud2lkdGg9MTgsIGZpZy5oZWlnaHQ9MTJ9DQoNCiMgRnVuY3Rpb24gdG8gY2hhbmdlIE9DUCB0byBiZSBtb3JlIGdlbmVyYWwNCnJlcGxhY2Vfb2NwMiA8LSBmdW5jdGlvbihkZikgew0KICBkZiAlPiUgDQogICAgbXV0YXRlKG9jcCA9IGNhc2Vfd2hlbigNCiAgICAgIGdyZXBsKCJDaGxvcmRhbmUiLCBvY3AsIGlnbm9yZS5jYXNlID0gVFJVRSkgfiAiQ2hsb3JkYW5lIiwgIA0KICAgICAgZ3JlcGwoIkVuZG9zdWxmYW4iLCBvY3AsIGlnbm9yZS5jYXNlID0gVFJVRSkgfiAiRW5kb3N1bGZhbiIsIA0KICAgICAgZ3JlcGwoIk5vbmFjaGxvciIsIG9jcCwgaWdub3JlLmNhc2UgPSBUUlVFKSB+ICJOb25hY2hsb3JlIiwgDQogICAgICBncmVwbCgiSGVwdGFjaGxvciIsIG9jcCwgaWdub3JlLmNhc2UgPSBUUlVFKSB+ICJIZXB0YWNobG9yIiwNCiAgICAgIGdyZXBsKCJUQ0REIiwgb2NwLCBpZ25vcmUuY2FzZSA9IFRSVUUpIH4gIlRDREQiLCANCiAgICAgIGdyZXBsKCJFbmRyaW4iLCBvY3AsIGlnbm9yZS5jYXNlID0gVFJVRSkgfiAiRW5kcmluIiwNCiAgICAgIGdyZXBsKCJIZXhhY2hsb3JvYmVuemVuZSIsIG9jcCwgaWdub3JlLmNhc2UgPSBUUlVFKSB+ICJIQ0giLA0KICAgICAgZ3JlcGwoIkxpbmRhbmUiLCBvY3AsIGlnbm9yZS5jYXNlID0gVFJVRSkgfiAiSENIIiwgDQogICAgICBncmVwbCgiSGV4YWNobG9yb2N5Y2xvaGV4YW5lIFxcKEhDSFxcKSIsIG9jcCwgaWdub3JlLmNhc2UgPSBUUlVFKSB+ICJIQ0giLA0KICAgICAgZ3JlcGwoImFscGhhLUhleGFjaGxvcm9jeWNsb2hleGFuZSBcXChhbHBoYS1IQ0hcXCkiLCBvY3AsIGlnbm9yZS5jYXNlID0gVFJVRSkgfiAiSENIIiwNCiAgICAgIGdyZXBsKCJiZXRhLUhleGFjaGxvcm9jeWNsb2hleGFuZSBcXChiZXRhLUhDSFxcKSIsIG9jcCwgaWdub3JlLmNhc2UgPSBUUlVFKSB+ICJIQ0giLA0KICAgICAgZ3JlcGwoImdhbW1hLUhleGFjaGxvcm9jeWNsb2hleGFuZSBcXChnYW1tYS1IQ0hcXCkiLCBvY3AsIGlnbm9yZS5jYXNlID0gVFJVRSkgfiAiSENIIiwNCiAgICAgIGdyZXBsKCJEaWNobG9yb2RpcGhlbnlsdHJpY2hsb3JvZXRoYW5lIFxcKEREVFxcKSIsIG9jcCwgaWdub3JlLmNhc2UgPSBUUlVFKSB+ICJERFQiLA0KICAgICAgZ3JlcGwoInAscC1EaWNobG9yb2RpcGhlbnlsdHJpY2hsb3JvZXRoYW5lIFxcKHAscC1ERFRcXCkiLCBvY3AsIGlnbm9yZS5jYXNlID0gVFJVRSkgfiAiRERUIiwNCiAgICAgIGdyZXBsKCJvLHAtRGljaGxvcm9kaXBoZW55bHRyaWNobG9yb2V0aGFuZSBcXChvLHAtRERUXFwpIiwgb2NwLCBpZ25vcmUuY2FzZSA9IFRSVUUpIH4gIkREVCIsDQogICAgICBncmVwbCgiRGljaGxvcm9kaXBoZW55bGRpY2hsb3JvZXRoYW5lIFxcKERERFxcKSIsIG9jcCwgaWdub3JlLmNhc2UgPSBUUlVFKSB+ICJEREQiLA0KICAgICAgZ3JlcGwoInAscC1EaWNobG9yb2RpcGhlbnlsZGljaGxvcm9ldGhhbmUgXFwocCxwLURERFxcKSIsIG9jcCwgaWdub3JlLmNhc2UgPSBUUlVFKSB+ICJEREQiLA0KICAgICAgZ3JlcGwoIm8scC1EaWNobG9yb2RpcGhlbnlsZGljaGxvcm9ldGhhbmUgXFwobyxwLURERFxcKSIsIG9jcCwgaWdub3JlLmNhc2UgPSBUUlVFKSB+ICJEREQiLA0KICAgICAgZ3JlcGwoIkRpY2hsb3JvZGlwaGVueWxkaWNobG9yb2V0aHlsZW5lIFxcKERERVxcKSIsIG9jcCwgaWdub3JlLmNhc2UgPSBUUlVFKSB+ICJEREUiLA0KICAgICAgZ3JlcGwoInAscC1EaWNobG9yb2RpcGhlbnlsZGljaGxvcm9ldGh5bGVuZSBcXChwLHAtRERFXFwpIiwgb2NwLCBpZ25vcmUuY2FzZSA9IFRSVUUpIH4gIkRERSIsDQogICAgICBncmVwbCgibyxwLURpY2hsb3JvZGlwaGVueWxkaWNobG9yb2V0aHlsZW5lIFxcKG8scC1EREVcXCkiLCBvY3AsIGlnbm9yZS5jYXNlID0gVFJVRSkgfiAiRERFIiwNCiAgICAgIFRSVUUgfiBvY3ANCiAgICApKQ0KfQ0KDQojIFRyYW5zZm9ybSB0aGUgZGF0YSANCmFsbHV2aWFsX2RhdGEgPC0gaW0gJT4lDQogIGxlZnRfam9pbihvY3AsIGJ5ID0gInN0dWR5X2lkIikgJT4lDQogIGxlZnRfam9pbihzdWIsIGJ5ID0gInN0dWR5X2lkIikgJT4lDQogIHNlcGFyYXRlX3Jvd3Moc3ViamVjdCwgc2VwID0gIixcXHMrIikgJT4lIA0KICBzZXBhcmF0ZV9yb3dzKG9jcCwgc2VwID0gIixcXHMrIikgJT4lIA0KICBzZXBhcmF0ZV9yb3dzKGltcGFjdF9icm9hZCwgc2VwID0gIixcXHMrIikgJT4lDQogIHJlcGxhY2Vfb2NwMigpICU+JQ0KICBmaWx0ZXIoIWdyZXBsKCJub3QgcmVwb3J0ZWQiLCBvY3AsIGlnbm9yZS5jYXNlID0gVFJVRSkpICU+JQ0KICBncm91cF9ieShvY3AsIHN1YmplY3QsIGltcGFjdF9icm9hZCkgJT4lDQogIHN1bW1hcmlzZShmcmVxID0gbigpLCAuZ3JvdXBzID0gJ2Ryb3AnKSAlPiUNCiAgZ3JvdXBfYnkob2NwKSAlPiUNCiAgZmlsdGVyKHN1bShmcmVxKSA+IDEwKSAlPiUgIA0KICBncm91cF9ieShpbXBhY3RfYnJvYWQpICU+JSANCiAgZmlsdGVyKHN1bShmcmVxKSA+IDUpICU+JSANCiAgbXV0YXRlKHN1YmplY3QgPSBmYWN0b3Ioc3ViamVjdCwgbGV2ZWxzID0gYygiRW52aXJvbm1lbnQiLCAiTm9uLWh1bWFuIGFuaW1hbCIsICJIdW1hbiIpLCBvcmRlcmVkID0gVFJVRSkpDQoNCiMgTWFrZSBhbGx1dmlhbCBwbG90DQphbGx1dmlhbF9wbG90X2V4cG9zdXJlIDwtIGFsbHV2aWFsX2RhdGEgJT4lIA0KICBnZ3Bsb3QoYWVzKGF4aXMxID0gb2NwLCBheGlzMiA9IHN1YmplY3QsIGF4aXMzID0gaW1wYWN0X2Jyb2FkLCB5ID0gZnJlcSkpICsNCiAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSBjKCJPcmdhbm9jaGxvcmluZSBQZXN0aWNpZGUiLCAiU3ViamVjdCIsICJJbXBhY3QiKSwgZXhwYW5kID0gYyguMDUsIC4xMCkpICsNCiAgeGxhYigiVmFyaWFibGVzIikgKw0KICB5bGFiKCJGcmVxdWVuY3kiKSArICANCiAgZ2VvbV9hbGx1dml1bShhZXMoZmlsbCA9IHN1YmplY3QpKSArDQogIGdlb21fc3RyYXR1bSh3aWR0aCA9IDEvMiwgZmlsbCA9ICJ3aGl0ZSIsIGNvbG9yID0gImJsYWNrIikgKw0KICBnZW9tX3RleHQoc3RhdCA9ICJzdHJhdHVtIiwgYWVzKGxhYmVsID0gYWZ0ZXJfc3RhdChzdHJhdHVtKSksIHNpemUgPSA1LCBmb250ZmFjZSA9ICJib2xkIikgKyAgDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLCAgDQogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCAgDQogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpICsgDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiLCBuYW1lID0gIlN1YmplY3QgQ2F0ZWdvcnkiKQ0KDQphbGx1dmlhbF9wbG90X2V4cG9zdXJlDQoNCiMgZ2dzYXZlKGhlcmUoImZpZ3VyZXMiLCAiYWxsdXZpYWxfcGxvdF9leHBvc3VyZV9zdWJqZWN0X2ltcGFjdC5wZGYiKSwgDQojICAgICAgICBwbG90ID0gYWxsdXZpYWxfcGxvdF9leHBvc3VyZSwgd2lkdGggPSAyNSwgaGVpZ2h0ID0gMTUsIHVuaXRzID0gImNtIiwgc2NhbGUgPSAyLCBkcGkgPSA4MDApDQojIGdnc2F2ZShoZXJlKCJmaWd1cmVzIiwgImFsbHV2aWFsX3Bsb3RfZXhwb3N1cmVfc3ViamVjdF9pbXBhY3QuanBnIiksIA0KIyAgICAgICAgcGxvdCA9IGFsbHV2aWFsX3Bsb3RfZXhwb3N1cmUsIHdpZHRoID0gMjUsIGhlaWdodCA9IDE1LCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KDQoNCiMgZ2dzYXZlKGhlcmUoImZpZ3VyZXMiLCAiZmlnczI5LnBkZiIpLCB3aWR0aCA9MTgsIGhlaWdodCA9IDEyLCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJmaWdzMjkuanBnIiksIHdpZHRoID0gMTgsIGhlaWdodCA9IDEyLCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KYGBgDQoNCiMjIEZpZ3VyZSAzDQpBIGJ1YmJsZSBwbG90IHNob3dpbmcgdGhlIGNvdW50cyBvZiBlYWNoIHBlc3RpY2lkZSBwZXIgaW1wYWN0IGluY2x1ZGVkIGluIGN1cnJlbnQgbWV0YS1hbmFseXNpcyBvbiB0aGUgaW1wYWN0cyBvZiBvcmdhbm9jaGxvcmluZSBwZXN0aWNpZGVzIA0KYGBge3IsZmlnLndpZHRoPTI1LCBmaWcuaGVpZ2h0PTE1fQ0KDQojIEpvaW4gdGhlIG9yZ2Fub2NobG9yaW5lIHBlc3RpY2lkZSBkZXRhaWxzIHdpdGggdGhlIGltcGFjdCBkZXRhaWxzDQpvY3BfaW0gPC0gbGVmdF9qb2luKG9jcCwgaW0gLHN1YiwgYnkgPSAic3R1ZHlfaWQiKSANCg0KIyBTZXBhcmF0ZSByb3dzIGluICJvY3BfaW0iDQpvY3BfaW0xIDwtIHNlcGFyYXRlX3Jvd3Mob2NwX2ltLCBvY3AgLCBzZXAgPSAiLCAiLCBjb252ZXJ0ID0gVFJVRSkNCg0KDQojIEdyb3VwIGJ5ICJvY3AiIGFuZCAiaW1wYWN0IiBhbmQgc3VtbWFyaXplIGNvdW50DQpvY3BfaW1fc3VtbWFyeSA8LSBvY3BfaW0xICU+JQ0KICBtdXRhdGUob2NwID0gc3RyX3RyaW0ob2NwKSwNCiAgICAgICAgIGltcGFjdF9icm9hZCA9IHN0cl90cmltKGltcGFjdF9icm9hZCkpICU+JQ0KICAgIHJlcGxhY2Vfb2NwMigpICU+JSANCiAgZ3JvdXBfYnkob2NwLCBpbXBhY3RfYnJvYWQpICU+JQ0KICBzdW1tYXJpc2UoY291bnQgPSBuKCksIC5ncm91cHMgPSAiZHJvcCIpICU+JSANCiAgbXV0YXRlKG9jcCA9IGlmZWxzZShncmVwbCgibm8gY2hlbWljYWwgY2xhc3NpZmljYXRpb24iLCBvY3AsIGlnbm9yZS5jYXNlID0gVFJVRSksICJubyBjaGVtaWNhbFxuIGNsYXNzaWZpY2F0aW9uIiwgb2NwKSkNCg0KIyBGaWx0ZXIgZm9yIHRvcCA4IHBlc3RpY2lkZXMgDQp0b3BfcGVzdGljaWRlcyA8LSBvY3BfaW1fc3VtbWFyeSAlPiUNCiAgZmlsdGVyKG9jcCAhPSAibm90IHJlcG9ydGVkIikgJT4lDQogIGdyb3VwX2J5KG9jcCkgJT4lDQogIHN1bW1hcmlzZSh0b3RhbF9jb3VudCA9IHN1bShjb3VudCkpICU+JQ0KICB0b3Bfbig4LCB0b3RhbF9jb3VudCkgJT4lDQogIHB1bGwob2NwKSANCg0KDQpvY3BfaW1fc3VtbWFyeV9maWx0ZXJlZCA8LSBvY3BfaW1fc3VtbWFyeSAlPiUNCiAgZmlsdGVyKG9jcCAlaW4lIHRvcF9wZXN0aWNpZGVzKQ0KDQpmaWczIDwtIG9jcF9pbV9zdW1tYXJ5X2ZpbHRlcmVkICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gZmN0X3JldihmY3RfcmVvcmRlcihpbXBhY3RfYnJvYWQsIGNvdW50LCAuZnVuID0gJ3N1bScpKSwNCiAgICAgICAgICAgICB5ID0gZmN0X3Jlb3JkZXIob2NwLCBjb3VudCwgLmZ1biA9ICdzdW0nKSwNCiAgICAgICAgICAgICBzaXplID0gY291bnQsDQogICAgICAgICAgICAgZmlsbCA9IGltcGFjdF9icm9hZCkpICsNCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBjb2xvciA9ICJ3aGl0ZSIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGNvdW50KSwgc2l6ZSA9IDIwLCBmb250ZmFjZSA9ICJib2xkIikgKw0KICBsYWJzKHRpdGxlID0gTlVMTCwgeCA9IE5VTEwsIHkgPU5VTEwpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDM1KSwgIA0KICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA0MCwgaGp1c3QgPSAxKSwgIA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKw0KICBzY2FsZV9zaXplX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDMwLCA4MCkpDQoNCmZpZzMNCg0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJmaWczLnBkZiIpLCB3aWR0aCA9IDQwLCBoZWlnaHQgPSAyNSwgdW5pdHMgPSAiY20iLCBzY2FsZSA9IDIsIGRwaSA9IDgwMCkNCiMgZ2dzYXZlKGhlcmUoImZpZ3VyZXMiLCAiZmlnMy5qcGciKSwgd2lkdGggPSA0MCwgaGVpZ2h0ID0gMjUsIHVuaXRzID0gImNtIiwgc2NhbGUgPSAyLCBkcGkgPSA4MDApDQogIA0KYGBgDQoNCiMgU2VjdGlvbiAzDQpUbyBpbnZlc3RpZ2F0ZSBnbG9iYWwgcmVzZWFyY2ggb3V0cHV0IGFuZCBjb2xsYWJvcmF0aW9uIG5ldHdvcmtzDQoNCiMjIEV4cGxvcmF0b3J5IGJpYmxpb21ldHJpYyBhbmFseXNpcw0KDQpgYGB7cixmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9MTB9DQojIFBlcmZvcm0gYmlibGlvbWV0cmljIGFuYWx5c2lzDQpiaWJsaW9tZXRyaWNfYW5hbHlzaXMgPC0gYmlibGlvQW5hbHlzaXMoYmliX3NjbykNCg0KIyBBZGp1c3QgcGxvdCBwYXJhbWV0ZXJzDQpwYXIoY2V4PTEuNSkNCg0KIyBFeHBsb3JlIHJlc3VsdHMNCnBsb3QoYmlibGlvbWV0cmljX2FuYWx5c2lzKQ0Kc3VtbWFyeShiaWJsaW9tZXRyaWNfYW5hbHlzaXMpDQpzdHIoYmlibGlvbWV0cmljX2FuYWx5c2lzKQ0KDQpgYGANCg0KIyMgQmFyIHBsb3Qgb2YgbW9zdCBwcm9kdWN0aXZlIGNvdW50cmllcw0KTW9zdCBwcm9kdWN0aXZlIGNvdW50cmllcyBmb3IgbWV0YS1hbmFseXNlcyBpbmNsdWRlZCBpbiB0aGUgc3lzdGVtYXRpYyByZXZpZXcgbWFwIEJsdWUgaXMgZm9yIHNpbmdsZSBjb3VudHJ5IHB1YmxpY2F0aW9ucyAoaS5lLiwgY291bnRyaWVzIHdpdGggYXV0aG9ycyBmcm9tIGEgc2luZ2xlIGNvdW50cnkpIGFuZCByZWQgaXMgZm9yIG11bHRpcGxlIGNvdW50cnkgcHVibGljYXRpb25zIChpLmUuLCBjb3VudHJpZXMgd2l0aCBhdXRob3JzIGZyb20gbXVsdGlwbGUgY291bnRyaWVzKS4NCmBgYHtyLGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD0xMH0NCiMgRXh0cmFjdCBjb3VudHJ5IGNvbGxhYm9yYXRpb24gaW5mb3JtYXRpb24NCmNvdW50cnlfZGF0YSA8LSBiaWJsaW9tZXRyaWNfYW5hbHlzaXMkQ291bnRyeUNvbGxhYm9yYXRpb24NCmNvdW50cnlfdGliYmxlIDwtIGFzX3RpYmJsZShjb3VudHJ5X2RhdGEpDQoNCiMgUmVzaGFwZSBkYXRhIGludG8gbG9uZyBmb3JtYXQNCmNvdW50cnlfdGliYmxlX2xvbmcgPC0gY291bnRyeV90aWJibGUgJT4lIA0KICBwaXZvdF9sb25nZXIoY29scyA9IGMoU0NQLCBNQ1ApLCBuYW1lc190byA9ICJDb3VudHJ5X0NvbGxhYm9yYXRpb24iLCB2YWx1ZXNfdG8gPSAidmFsdWUiKQ0KDQojIFN1bW1hcml6ZSBhbmQgZmlsdGVyIGZvciB0b3AgdGVuIGNvdW50cmllcw0KdG9wX2NvdW50cmllcyA8LSBjb3VudHJ5X3RpYmJsZV9sb25nICU+JQ0KICBncm91cF9ieShDb3VudHJ5KSAlPiUNCiAgc3VtbWFyaXplKFRvdGFsID0gc3VtKHZhbHVlKSkgJT4lDQogIGFycmFuZ2UoZGVzYyhUb3RhbCkpICU+JQ0KICBzbGljZV9oZWFkKG4gPSAxMCkNCg0KIyBGaWx0ZXIgb3JpZ2luYWwgZGF0YXNldCB0byBrZWVwIG9ubHkgdGhlIHRvcCB0ZW4gY291bnRyaWVzDQpjb3VudHJ5X3RpYmJsZV9sb25nX2ZpbHRlcmVkIDwtIGNvdW50cnlfdGliYmxlX2xvbmcgJT4lDQogIGZpbHRlcihDb3VudHJ5ICVpbiUgdG9wX2NvdW50cmllcyRDb3VudHJ5KQ0KDQojIENyZWF0ZSBzdGFja2VkIGJhciBwbG90DQpiYXJfcGxvdF9jb3VudHJpZXMgPC0gZ2dwbG90KGNvdW50cnlfdGliYmxlX2xvbmdfZmlsdGVyZWQsIGFlcyhmaWxsID0gQ291bnRyeV9Db2xsYWJvcmF0aW9uLCB5ID0gdmFsdWUsIHggPSBDb3VudHJ5KSkgKw0KICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIsIHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIG9yZ2Fub2NobG9yVEhFTUUoKQ0KDQpiYXJfcGxvdF9jb3VudHJpZXMNCg0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJiYXJfcGxvdF9jb3VudHJpZXMucGRmIiksIHdpZHRoID0gMjUsIGhlaWdodCA9IDE1LCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJiYXJfcGxvdF9jb3VudHJpZXMuanBnIiksIHdpZHRoID0gMjUsIGhlaWdodCA9IDE1LCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KDQoNCmBgYA0KDQojIyAgQmFyIHBsb3Qgb2YgdG9wIGF1dGhvcnMNCg0KYGBge3IsZmlnLndpZHRoPTE2LCBmaWcuaGVpZ2h0PTEwfQ0KYXV0aG9yc19kYXRhIDwtIGJpYmxpb21ldHJpY19hbmFseXNpcyRBdXRob3JzDQphdXRob3JzX3RpYmJsZSA8LSBhc190aWJibGUoYXV0aG9yc19kYXRhKQ0KDQojIFNsaWNlIHRvcCAxMCBhdXRob3JzDQphdXRob3JzX3RpYmJsZV9maWx0ZXJlZCA8LSBhdXRob3JzX3RpYmJsZSAlPiUNCiAgc2xpY2VfaGVhZChuID0gMTApDQoNCmJhcl9wbG90X2F1dGhvcnMgPC0gZ2dwbG90KGF1dGhvcnNfdGliYmxlX2ZpbHRlcmVkLCBhZXMoeSA9IG4sIHggPSByZW9yZGVyKEFVLCBuKSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMC44LCBhbHBoYSA9IDAuNywgZmlsbCA9ICIjMWI5ZTc3IikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gbiwgeSA9IG4vMiksIGhqdXN0ID0gMC41LCBjb2xvciA9ICJibGFjayIsIHNpemUgPSAxMCkgKw0KICBjb29yZF9mbGlwKCkgKw0KICBvcmdhbm9jaGxvclRIRU1FKCkNCg0KYmFyX3Bsb3RfYXV0aG9ycw0KDQojIGdnc2F2ZShoZXJlKCJmaWd1cmVzIiwgImJhcl9wbG90X3RvcF9hdXRob3JzLnBkZiIpLCB3aWR0aCA9IDI1LCBoZWlnaHQgPSAxNSwgdW5pdHMgPSAiY20iLCBzY2FsZSA9IDIsIGRwaSA9IDgwMCkNCiMgZ2dzYXZlKGhlcmUoImZpZ3VyZXMiLCAiYmFyX3Bsb3RfdG9wX2F1dGhvcnMuanBnIiksIHdpZHRoID0gMjUsIGhlaWdodCA9IDE1LCB1bml0cyA9ICJjbSIsIHNjYWxlID0gMiwgZHBpID0gODAwKQ0KDQoNCmBgYA0KDQojIyBGaWd1cmUgNA0KSGVhdCBtYXAgb2Ygd29ybGQgc2hvd2luZyB0aGUgY291bnRyeS1sZXZlbCBjb3VudHMgZm9yIGZpcnN0IGF1dGhvcnPigJkgY291bnRyeSBvZiBhZmZpbGlhdGlvbiBvZiBtZXRhLWFuYWx5c2lzIGludmVzdGlnYXRpbmcgdGhlIGltcGFjdHMgb2Ygb3JnYW5vY2hsb3JpbmUgcGVzdGljaWRlcy4gR3JleSBpbmRpY2F0ZXMgbm8gcHVibGljYXRpb25zIGFmZmlsaWF0ZWQgd2l0aCBhIGdpdmVuIGNvdW50cnkgaW4gb3VyIGRhdGEgc2V0LiANCmBgYHtyLGZpZy53aWR0aD0gMjEsIGZpZy5oZWlnaHQ9MTJ9DQojIEV4dHJhY3QgY291bnRyeSBpbmZvcm1hdGlvbiBmcm9tIHRoZSAiQVUxX0NPIiBhbmQgIkFVX0NPIiBmaWVsZHMgb2YgdGhlICJiaWJfc2NvIiBkYXRhc2V0DQpiaWJtYXAgPC0gbWV0YVRhZ0V4dHJhY3Rpb24oYmliX3NjbywgRmllbGQgPSAiQVUxX0NPIiwgc2VwID0gIjsiKSANCmJpYm1hcCA8LSBtZXRhVGFnRXh0cmFjdGlvbihiaWJtYXAsIEZpZWxkID0gIkFVX0NPIiwgc2VwID0gIjsiKSANCg0KIyBDcmVhdGUgYSBkYXRhIGZyYW1lIHdpdGggY291bnRzIG9mIGFydGljbGVzIGZyb20gZWFjaCBjb3VudHJ5DQpmaXJzdGNvdW50cnljb3VudHMgPC0gYmlibWFwICU+JSANCiAgZ3JvdXBfYnkoQVUxX0NPKSAlPiUgDQogIGNvdW50KCkgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKEFVMV9DTykpICANCg0KIyBMb2FkIHdvcmxkIG1hcCBkYXRhIGFuZCByZW1vdmUgY291bnRyaWVzIHdpdGggbG9uZ2l0dWRlID4xODAgdG8gbWFrZSBhbiBlcXVhbCBwcm9qZWN0aW9uLWxpa2UgbWFwDQp3b3JsZF9tYXAgPC0gbWFwX2RhdGEoIndvcmxkIikgJT4lIA0KICBmaWx0ZXIoISBsb25nID4gMTgwKQ0KDQojIEZvcm1hdCBjb3VudHJ5IG5hbWVzIHRvIG1hdGNoIHJlZ2lvbnMgb24gdGhlIHdvcmxkIG1hcA0KZmlyc3Rjb3VudHJ5Y291bnRzJHJlZ2lvbiA8LSBzdHJfdG9fdGl0bGUoZmlyc3Rjb3VudHJ5Y291bnRzJEFVMV9DTykNCmZpcnN0Y291bnRyeWNvdW50cyRyZWdpb25bZmlyc3Rjb3VudHJ5Y291bnRzJHJlZ2lvbiA9PSAiVXNhIl0gPC0gIlVTQSIgDQpmaXJzdGNvdW50cnljb3VudHMkcmVnaW9uW2ZpcnN0Y291bnRyeWNvdW50cyRyZWdpb24gPT0gIktvcmVhIl0gPC0gIlNvdXRoIEtvcmVhIg0KZmlyc3Rjb3VudHJ5Y291bnRzJHJlZ2lvbltmaXJzdGNvdW50cnljb3VudHMkcmVnaW9uID09ICJVbml0ZWQgS2luZ2RvbSJdIDwtICJVSyINCg0KIyBKb2luIGNvdW50IGRhdGEgd2l0aCBtYXAgZGF0YSBhbmQgc2V0IG1pc3NpbmcgY291bnRzIHRvIHplcm8NCmVtcHR5bWFwIDwtIHRpYmJsZShyZWdpb24gPSB1bmlxdWUod29ybGRfbWFwJHJlZ2lvbiksIG4gPSByZXAoMCxsZW5ndGgodW5pcXVlKHdvcmxkX21hcCRyZWdpb24pKSkpDQpmdWxsbWFwIDwtIGxlZnRfam9pbihlbXB0eW1hcCwgZmlyc3Rjb3VudHJ5Y291bnRzLCBieSA9ICJyZWdpb24iKQ0KZnVsbG1hcCRuIDwtIGZ1bGxtYXAkbi54ICsgZnVsbG1hcCRuLnkNCmZ1bGxtYXAkbltpcy5uYShmdWxsbWFwJG4pXSA8LSAwDQoNCmZpZzQgPC0gZnVsbG1hcCAlPiUNCiAgZ2dwbG90KGFlcyhmaWxsID0gbiwgbWFwX2lkID0gcmVnaW9uKSkgKw0KICBnZW9tX21hcChtYXAgPSB3b3JsZF9tYXAsIGNvbG9yID0gImdyYXk1MCIpICsNCiAgZXhwYW5kX2xpbWl0cyh4ID0gd29ybGRfbWFwJGxvbmcsIHkgPSB3b3JsZF9tYXAkbGF0KSArDQogIGNvb3JkX21hcCgibWVyY2F0b3IiLCB4bGltID0gYygtMTgwLCAxODApLCB5bGltID0gYygtNTAsIDkwKSkgKyAgDQogIHRoZW1lKA0KICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwgIA0KICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksICANCiAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwNCiAgICBsZWdlbmQuYm94ID0gImhvcml6b250YWwiLCAgDQogICAgbGVnZW5kLmJveC5qdXN0ID0gImNlbnRlciIsICANCiAgICBsZWdlbmQubWFyZ2luID0gbWFyZ2luKHQgPSAxMCwgdW5pdCA9ICJwdCIpLCAgDQogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwgIA0KICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIpLCAgDQogICAgbGVnZW5kLmtleS53aWR0aCA9IHVuaXQoMzAsICJtbSIpLCANCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKQ0KICApICsNCiAgc2NhbGVfZmlsbF9ncmFkaWVudCgNCiAgICBsb3cgPSAiIzk4RkI5OCIsIGhpZ2ggPSAiIzAwNjQwMCIsDQogICAgbmFtZSA9ICJGaXJzdCBBdXRob3IgQ291bnQiLCAgDQogICAgbmEudmFsdWUgPSAiZ3JheTcwIiwNCiAgICBsaW1pdHMgPSBjKDEsIDIwKQ0KICApICsNCiAgZ3VpZGVzKA0KICAgIGZpbGwgPSBndWlkZV9jb2xvdXJiYXIoDQogICAgICBiYXJ3aWR0aCA9IHVuaXQoMjEwLCB1bml0cyA9ICJtbSIpLA0KICAgICAgYmFyaGVpZ2h0ID0gdW5pdCg1LCB1bml0cyA9ICJtbSIpDQogICAgKQ0KICApDQoNCmZpZzQNCg0KICMgZ2dzYXZlKGhlcmUoImZpZ3VyZXMiLCAiZmlnNC5wZGYiKSwgd2lkdGggPSAyMSwgaGVpZ2h0ID0gMTIsIHVuaXRzID0gImNtIiwgc2NhbGUgPSAyLCBkcGkgPSA4MDApDQogIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJmaWc0LmpwZyIpLCB3aWR0aCA9IDIxLCBoZWlnaHQgPSAxMiwgdW5pdHMgPSAiY20iLCBzY2FsZSA9IDIsIGRwaSA9IDgwMCkNCg0KYGBgDQoNCiMjIEV1cm9wZSBtYXAgb2YgZmlyc3QtYXV0aG9yIGFmZmlsaWF0aW9ucw0KSGVhdCBtYXAgb2YgRXVyb3BlIHNob3dpbmcgdGhlIGNvdW50cnktbGV2ZWwgY291bnRzIGZvciBmaXJzdCBhdXRob3Jz4oCZIGNvdW50cnkgb2YgYWZmaWxpYXRpb24gb2YgbWV0YS1hbmFseXNpcyBpbnZlc3RpZ2F0aW5nIHRoZSBpbXBhY3RzIG9mIG9yZ2Fub2NobG9yaW5lIHBlc3RpY2lkZXMuIEdyZXkgaW5kaWNhdGVzIG5vIHB1YmxpY2F0aW9ucyBhZmZpbGlhdGVkIHdpdGggYSBnaXZlbiBjb3VudHJ5IGluIG91ciBkYXRhIHNldC4gDQpgYGB7cixmaWcud2lkdGg9IDIxLCBmaWcuaGVpZ2h0PTEyfQ0KaGVhdF9tYXBfZXVyb3BlIDwtIGZ1bGxtYXAgJT4lDQogIGdncGxvdChhZXMoZmlsbCA9IG4sIG1hcF9pZCA9IHJlZ2lvbikpICsNCiAgZ2VvbV9tYXAobWFwID0gd29ybGRfbWFwLCBjb2xvciA9ICJncmF5NTAiKSArDQogIGNvb3JkX21hcCgibWVyY2F0b3IiLCB5bGltID0gYygzNSwgNjUpLCB4bGltID0gYygtMzUsIDQ1KSkgKyANCiAgdGhlbWUoDQogICAgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLCAgDQogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgIA0KICAgIGxlZ2VuZC5ib3ggPSAiaG9yaXpvbnRhbCIsICANCiAgICBsZWdlbmQuYm94Lmp1c3QgPSAiY2VudGVyIiwgIA0KICAgIGxlZ2VuZC5tYXJnaW4gPSBtYXJnaW4odCA9IDEwLCB1bml0ID0gInB0IiksICANCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpLCAgDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCwgZmFjZSA9ICJib2xkIiksICANCiAgICBsZWdlbmQua2V5LndpZHRoID0gdW5pdCgzMCwgIm1tIiksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsDQogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIikNCiAgKSArDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQoDQogICAgbG93ID0gIiM5OEZCOTgiLCBoaWdoID0gIiMwMDY0MDAiLA0KICAgIG5hbWUgPSAiRmlyc3QgQXV0aG9yIENvdW50IiwgbmEudmFsdWUgPSAiZ3JheTcwIiwNCiAgICBsaW1pdHMgPSBjKDEsIDEwKSwgYnJlYWtzID0gc2VxKDAsIDEwLCBsZW5ndGgub3V0ID0gNikNCiAgKQ0KDQpoZWF0X21hcF9ldXJvcGUNCg0KIyBnZ3NhdmUoaGVyZSgiZmlndXJlcyIsICJoZWF0X21hcF9ldXJvcGVfYXV0aG9ycy5wZGYiKSwgd2lkdGggPSAyNSwgaGVpZ2h0ID0gMTUsIHVuaXRzID0gImNtIiwgc2NhbGUgPSAyLCBkcGkgPSA4MDApDQojIGdnc2F2ZShoZXJlKCJmaWd1cmVzIiwgImhlYXRfbWFwX2V1cm9wZV9hdXRob3JzLmpwZyIpLCB3aWR0aCA9IDI1LCBoZWlnaHQgPSAxNSwgdW5pdHMgPSAiY20iLCBzY2FsZSA9IDIsIGRwaSA9IDgwMCkNCg0KYGBgDQoNCg0KIyMgQ2hvcmQgZGlhZ3JhbSBvZiBjb3VudHJ5IGNvbGxhYm9yYXRpb25zDQpDaG9yZCBkaWFncmFtIG9mIGNvbGxhYm9yYXRpb25zIGFjcm9zcyBjb3VudHJpZXMuIENvdW50cmllcyByZXByZXNlbnQgdGhlIGxvY2F0aW9uIG9mIHRoZSBwcmltYXJ5IGF1dGhvcnPigJkgYWZmaWxpYXRlZCBpbnN0aXR1dGlvbi4gDQpgYGB7cixmaWcud2lkdGg9IDEyLCBmaWcuaGVpZ2h0PTEyfQ0KanBlZyhmaWxlbmFtZSA9IGhlcmUoImZpZ3VyZXMiLCAiY2hvcmRfZGlhZ3JhbV9jb3VudHJ5X2NvbGxhYm9yYXRpb25zLmpwZyIpLCB3aWR0aCA9IDgwMCwgaGVpZ2h0ID0gODAwKQ0KDQojIEV4dHJhY3QgY291bnRyaWVzIGZyb20gdGhlIGFmZmlsaWF0aW9ucw0KYmliX3NjbzIgPC0gbWV0YVRhZ0V4dHJhY3Rpb24oYmliX3NjbywgRmllbGQgPSAiQVVfQ08iLCBzZXAgPSAiOyIpDQoNCiMgQ3JlYXRlIGEgbmV0d29yayBtYXRyaXggb2YgY29sbGFib3JhdGlvbnMgYmV0d2VlbiBjb3VudHJpZXMNCk5ldE1hdHJpeF9jb3VudHJ5IDwtIGJpYmxpb05ldHdvcmsoYmliX3NjbzIsIGFuYWx5c2lzID0gImNvbGxhYm9yYXRpb24iLCBuZXR3b3JrID0gImNvdW50cmllcyIsIHNlcCA9ICI7IikNCk5ldE1hdHJpeF9jb3VudHJ5IDwtIGFzLm1hdHJpeChOZXRNYXRyaXhfY291bnRyeSkNCg0KIyBSZW1vdmUgbG93ZXIgdHJpYW5nbGUgZHVwbGljYXRpb24NCk5ldE1hdHJpeF9jb3VudHJ5W2xvd2VyLnRyaShOZXRNYXRyaXhfY291bnRyeSldIDwtIDAgDQoNCiMgU3RhbmRhcmRpemUgc29tZSBjb3VudHJ5IG5hbWVzDQpjb2xuYW1lcyhOZXRNYXRyaXhfY291bnRyeSkgPC0gc3RyX3RvX3RpdGxlKGNvbG5hbWVzKE5ldE1hdHJpeF9jb3VudHJ5KSkNCnJvd25hbWVzKE5ldE1hdHJpeF9jb3VudHJ5KSA8LSBzdHJfdG9fdGl0bGUocm93bmFtZXMoTmV0TWF0cml4X2NvdW50cnkpKQ0KY29sbmFtZXMoTmV0TWF0cml4X2NvdW50cnkpW2NvbG5hbWVzKE5ldE1hdHJpeF9jb3VudHJ5KSA9PSAiVXNhIl0gPC0gIlVTQSINCnJvd25hbWVzKE5ldE1hdHJpeF9jb3VudHJ5KVtyb3duYW1lcyhOZXRNYXRyaXhfY291bnRyeSkgPT0gIlVzYSJdIDwtICJVU0EiDQpjb2xuYW1lcyhOZXRNYXRyaXhfY291bnRyeSlbY29sbmFtZXMoTmV0TWF0cml4X2NvdW50cnkpID09ICJVbml0ZWQgS2luZ2RvbSJdIDwtICJVSyINCnJvd25hbWVzKE5ldE1hdHJpeF9jb3VudHJ5KVtyb3duYW1lcyhOZXRNYXRyaXhfY291bnRyeSkgPT0gIlVuaXRlZCBLaW5nZG9tIl0gPC0gIlVLIg0KDQojIFNldCB1cCBjaXJjb3MgcGFyYW1ldGVycw0KY2lyY29zLnBhcihjZWxsLnBhZGRpbmcgPSBjKDAsIDAsIDAsIDApLCB0cmFjay5tYXJnaW4gPSBjKDAsIDApKQ0KDQojIENyZWF0ZSBjaG9yZCBkaWFncmFtDQpjaG9yZERpYWdyYW0oTmV0TWF0cml4X2NvdW50cnksIGFubm90YXRpb25UcmFjayA9ICJncmlkIiwgcHJlQWxsb2NhdGVUcmFja3MgPSAxKQ0KDQojIExhYmVsIGVhY2ggc2VjdG9yIHdpdGggaXRzIG5hbWUNCmNpcmNvcy50cmFja1Bsb3RSZWdpb24odHJhY2suaW5kZXggPSAxLCBiZy5ib3JkZXIgPSBOQSwgcGFuZWwuZnVuID0gZnVuY3Rpb24oeCwgeSkgew0KICB4bGltICAgICAgID0gZ2V0LmNlbGwubWV0YS5kYXRhKCJ4bGltIikNCiAgeWxpbSAgICAgICA9IGdldC5jZWxsLm1ldGEuZGF0YSgieWxpbSIpDQogIHNlY3Rvci5uYW1lPSBnZXQuY2VsbC5tZXRhLmRhdGEoInNlY3Rvci5pbmRleCIpDQogIGNpcmNvcy50ZXh0KG1lYW4oeGxpbSksIHlsaW1bMV0gKyAwLjIsIHNlY3Rvci5uYW1lLCANCiAgICAgICAgICAgICAgZmFjaW5nID0gImNsb2Nrd2lzZSIsIG5pY2VGYWNpbmcgPSBUUlVFLCBhZGogPSBjKDAsIDApKQ0KICBjaXJjb3MuYXhpcyhoID0gInRvcCIsIGxhYmVscy5jZXggPSAwLjUsIG1ham9yLnRpY2subGVuZ3RoID0gMC4yLCANCiAgICAgICAgICAgICAgc2VjdG9yLmluZGV4ID0gc2VjdG9yLm5hbWUsIHRyYWNrLmluZGV4ID0gMikNCn0pDQoNCmRldi5vZmYoKQ0KDQpgYGANCg0KIyMgQ2hvcmQgZGlhZ3JhbSAobm8gd2l0aGluLWNvdW50cnkgY29sbGFib3JhdGlvbnMpDQpDaG9yZCBkaWFncmFtIGlsbHVzdHJhdGlvbiBvZiBjb2xsYWJvcmF0aW9ucyBhY3Jvc3MgY291bnRyaWVzLiBDb3VudHJpZXMgcmVwcmVzZW50IHRoZSBsb2NhdGlvbiBvZiB0aGUgcHJpbWFyeSBhdXRob3Jz4oCZIGFmZmlsaWF0ZWQgaW5zdGl0dXRpb24uIENvbGxhYm9yYXRpb25zIHdpdGhpbiBjb3VudHJpZXMgYXJlIG5vdCBzaG93bi4NCmBgYHtyLGZpZy53aWR0aD0gMTIsIGZpZy5oZWlnaHQ9MTJ9DQpqcGVnKGZpbGVuYW1lID0gaGVyZSgiZmlndXJlcyIsICJjaG9yZF9kaWFncmFtX25vX3dpdGhpbl9jb3VudHJ5LmpwZyIpLCB3aWR0aCA9IDgwMCwgaGVpZ2h0ID0gODAwKQ0KDQojIFJlbW92ZSBkaWFnb25hbCAod2l0aGluLWNvdW50cnkpIGNvbGxhYm9yYXRpb25zDQpkaWFnKE5ldE1hdHJpeF9jb3VudHJ5KSA8LSAwDQoNCiMgQ3JlYXRlIGNob3JkIGRpYWdyYW0NCmNob3JkRGlhZ3JhbShOZXRNYXRyaXhfY291bnRyeSwgYW5ub3RhdGlvblRyYWNrID0gImdyaWQiLCBwcmVBbGxvY2F0ZVRyYWNrcyA9IDEpDQoNCiMgTGFiZWwgZWFjaCBzZWN0b3INCmNpcmNvcy50cmFja1Bsb3RSZWdpb24odHJhY2suaW5kZXggPSAxLCBwYW5lbC5mdW4gPSBmdW5jdGlvbih4LCB5KSB7DQogIHhsaW0gICAgICAgPSBnZXQuY2VsbC5tZXRhLmRhdGEoInhsaW0iKQ0KICB5bGltICAgICAgID0gZ2V0LmNlbGwubWV0YS5kYXRhKCJ5bGltIikNCiAgc2VjdG9yLm5hbWU9IGdldC5jZWxsLm1ldGEuZGF0YSgic2VjdG9yLmluZGV4IikNCiAgY2lyY29zLnRleHQobWVhbih4bGltKSwgeWxpbVsxXSArIDAuMiwgc2VjdG9yLm5hbWUsIA0KICAgICAgICAgICAgICBmYWNpbmcgPSAiY2xvY2t3aXNlIiwgbmljZUZhY2luZyA9IFRSVUUsIGFkaiA9IGMoMCwgMC41KSkNCiAgY2lyY29zLmF4aXMoaCA9ICJ0b3AiLCBsYWJlbHMuY2V4ID0gMC41LCBtYWpvci50aWNrLmxlbmd0aCA9IDAuMiwgDQogICAgICAgICAgICAgIHNlY3Rvci5pbmRleCA9IHNlY3Rvci5uYW1lLCB0cmFjay5pbmRleCA9IDIpDQp9LCBiZy5ib3JkZXIgPSBOQSkNCg0KZGV2Lm9mZigpDQoNCmBgYA0KDQojIyBGaWd1cmUgNGINCkNob3JkIGRpYWdyYW0gaWxsdXN0cmF0aW9uIG9mIGNvbGxhYm9yYXRpb25zIGFjcm9zcyBjb250aW5lbnRzLiBDb250aW5lbnRzIHJlcHJlc2VudCB0aGUgbG9jYXRpb24gb2YgdGhlIHByaW1hcnkgYXV0aG9yc+KAmSBhZmZpbGlhdGVkIGluc3RpdHV0aW9uLiBDb2xsYWJvcmF0aW9ucyB3aXRoaW4gY291bnRyaWVzIGFyZSBub3Qgc2hvd24uDQpgYGB7cixmaWcud2lkdGg9IDEyLCBmaWcuaGVpZ2h0PTEyfQ0KIyBDb3B5IHRoZSBjb3VudHJ5IG1hdHJpeCBpbnRvIGEg4oCcY29udGluZW504oCdIG1hdHJpeA0KTmV0TWF0cml4X2NvbnRpbmVudCA8LSBOZXRNYXRyaXhfY291bnRyeQ0KDQojIFJlbmFtZSBjb3VudHJpZXMgdG8gY29udGluZW50cw0KY29sbmFtZXMoTmV0TWF0cml4X2NvbnRpbmVudClbY29sbmFtZXMoTmV0TWF0cml4X2NvbnRpbmVudCkgPT0gIlVzYSJdIDwtICJOb3J0aCBBbWVyaWNhIg0Kcm93bmFtZXMoTmV0TWF0cml4X2NvbnRpbmVudClbcm93bmFtZXMoTmV0TWF0cml4X2NvbnRpbmVudCkgPT0gIlVzYSJdIDwtICJOb3J0aCBBbWVyaWNhIg0KDQpjb2xuYW1lcyhOZXRNYXRyaXhfY29udGluZW50KVtjb2xuYW1lcyhOZXRNYXRyaXhfY29udGluZW50KSA9PSAiU3BhaW4iXSA8LSAiRXVyb3BlIg0Kcm93bmFtZXMoTmV0TWF0cml4X2NvbnRpbmVudClbcm93bmFtZXMoTmV0TWF0cml4X2NvbnRpbmVudCkgPT0gIlNwYWluIl0gPC0gIkV1cm9wZSINCg0KIyAuLi4gKHJlbWFpbmRlciBvZiB5b3VyIHJlbmFtaW5nIGZvciBlYWNoIGNvdW50cnkg4oaSIGNvbnRpbmVudCkgLi4uDQoNCiMgQ29sbGFwc2UgaW50byBzdW1tZWQgY29udGluZW50cyBtYXRyaXgNCm1lcmdlX21hdHJpeCAgIDwtIHQocm93c3VtKHQoTmV0TWF0cml4X2NvbnRpbmVudCksIGdyb3VwID0gY29sbmFtZXMoTmV0TWF0cml4X2NvbnRpbmVudCksIG5hLnJtID0gVFJVRSkpDQptZXJnZV9tYXRyaXgyICA8LSByb3dzdW0obWVyZ2VfbWF0cml4LCBncm91cCA9IHJvd25hbWVzKG1lcmdlX21hdHJpeCkpDQpkaWFnKG1lcmdlX21hdHJpeDIpIDwtIDAgICMgcmVtb3ZlIGRpYWdvbmFsIGlmIHlvdSBkbyBub3Qgd2FudCB3aXRoaW4tY29udGluZW50IGNvbGxhYm9yYXRpb25zDQoNCiMgQ3JlYXRlIHRoZSBjaG9yZCBkaWFncmFtDQpjaG9yZERpYWdyYW1Gcm9tTWF0cml4KG1lcmdlX21hdHJpeDIpDQoNCiMgT3B0aW9uYWxseSBkZWZpbmUgY29sb3IgcGFsZXR0ZQ0KbXlfY29sb3JzIDwtIGMoIiMxQjlFNzciLCAiI0Q5NUYwMiIsICIjNzU3MEIzIiwgIiNFNkFCMDIiKQ0KbXlfY29sb3JzIDwtIHJlcChteV9jb2xvcnMsIGxlbmd0aC5vdXQgPSBuY29sKG1lcmdlX21hdHJpeDIpKQ0KDQpqcGVnKCJmaWd1cmVzL2NvbnRpbmVudF9jaG9yZF9kaWFncmFtLmpwZyIsIHdpZHRoID0gMjUsIGhlaWdodCA9IDI1LCB1bml0cyA9ICJjbSIsIHJlcyA9IDMwMCkNCg0KIyBEcmF3IGNob3JkIGRpYWdyYW0gd2l0aCBzb21lIHN0eWxpbmcNCmNob3JkRGlhZ3JhbShtZXJnZV9tYXRyaXgyLCANCiAgICAgICAgICAgICBhbm5vdGF0aW9uVHJhY2sgPSAiZ3JpZCIsIA0KICAgICAgICAgICAgIGFubm90YXRpb25UcmFja0hlaWdodCA9IG1tX2goNyksIA0KICAgICAgICAgICAgIHByZUFsbG9jYXRlVHJhY2tzID0gMSwNCiAgICAgICAgICAgICBncmlkLmNvbCA9IG15X2NvbG9ycykNCg0KIyBBZGQgdHJhY2sgdG8gbGFiZWwgZWFjaCBzZWN0b3INCmNpcmNvcy50cmFja1Bsb3RSZWdpb24odHJhY2suaW5kZXggPSAxLCBwYW5lbC5mdW4gPSBmdW5jdGlvbih4LCB5KSB7DQogIHhsaW0gICAgICAgPSBnZXQuY2VsbC5tZXRhLmRhdGEoInhsaW0iKQ0KICB5bGltICAgICAgID0gZ2V0LmNlbGwubWV0YS5kYXRhKCJ5bGltIikNCiAgc2VjdG9yLm5hbWU9IGdldC5jZWxsLm1ldGEuZGF0YSgic2VjdG9yLmluZGV4IikNCiAgY2lyY29zLnRleHQobWVhbih4bGltKSwgeWxpbVsxXSwgc2VjdG9yLm5hbWUsIA0KICAgICAgICAgICAgICBmYWNpbmcgPSAiYmVuZGluZy5pbnNpZGUiLCBuaWNlRmFjaW5nID0gVFJVRSwgDQogICAgICAgICAgICAgIGFkaiA9IGMoMC41LCAxLjc1KSwgY29sID0gIndoaXRlIiwgY2V4ID0gMS4yKQ0KfSwgYmcuYm9yZGVyID0gTkEpDQoNCmRldi5vZmYoKQ0KDQoNCmBgYA0KDQojIyBDaG9yZCBkaWFncmFtIG9mIGNvbGxhYm9yYXRpb25zIGFjcm9zcyBjb250aW5lbnRzDQpDaG9yZCBkaWFncmFtIGlsbHVzdHJhdGlvbiBvZiBjb2xsYWJvcmF0aW9ucyBhY3Jvc3MgZGlzY2lwbGluZXMuIERpc2NpcGxpbmVzIGhhdmUgYmVlbiBhbGxvY2F0ZWQgYmFzZWQgb24gdGhlIEpvdXJuYWwgQ2l0YXRpb24gQ2F0ZWdvcmllcyBvbiBXZWIgb2YgU2NpZW5jZS4gQ29sbGFib3JhdGlvbnMgd2l0aGluIGRpc2NpcGxpbmVzIGFyZSBub3Qgc2hvd24uDQpgYGB7cixmaWcud2lkdGg9IDEyLCBmaWcuaGVpZ2h0PTEyfQ0KIyBDb3B5IHRoZSBjb3VudHJ5IG1hdHJpeCBpbnRvIGEg4oCcY29udGluZW504oCdIG1hdHJpeA0KTmV0TWF0cml4X2NvbnRpbmVudCA8LSBOZXRNYXRyaXhfY291bnRyeQ0KDQojIFJlbmFtZSBjb3VudHJpZXMgdG8gY29udGluZW50cw0KY29sbmFtZXMoTmV0TWF0cml4X2NvbnRpbmVudClbY29sbmFtZXMoTmV0TWF0cml4X2NvbnRpbmVudCkgPT0gIlVzYSJdIDwtICJOb3J0aCBBbWVyaWNhIg0Kcm93bmFtZXMoTmV0TWF0cml4X2NvbnRpbmVudClbcm93bmFtZXMoTmV0TWF0cml4X2NvbnRpbmVudCkgPT0gIlVzYSJdIDwtICJOb3J0aCBBbWVyaWNhIg0KDQpjb2xuYW1lcyhOZXRNYXRyaXhfY29udGluZW50KVtjb2xuYW1lcyhOZXRNYXRyaXhfY29udGluZW50KSA9PSAiU3BhaW4iXSA8LSAiRXVyb3BlIg0Kcm93bmFtZXMoTmV0TWF0cml4X2NvbnRpbmVudClbcm93bmFtZXMoTmV0TWF0cml4X2NvbnRpbmVudCkgPT0gIlNwYWluIl0gPC0gIkV1cm9wZSINCg0KIyAuLi4gKHJlbWFpbmRlciBvZiB5b3VyIHJlbmFtaW5nIGZvciBlYWNoIGNvdW50cnkg4oaSIGNvbnRpbmVudCkgLi4uDQoNCiMgQ29sbGFwc2UgaW50byBzdW1tZWQgY29udGluZW50cyBtYXRyaXgNCm1lcmdlX21hdHJpeCAgIDwtIHQocm93c3VtKHQoTmV0TWF0cml4X2NvbnRpbmVudCksIGdyb3VwID0gY29sbmFtZXMoTmV0TWF0cml4X2NvbnRpbmVudCksIG5hLnJtID0gVFJVRSkpDQptZXJnZV9tYXRyaXgyICA8LSByb3dzdW0obWVyZ2VfbWF0cml4LCBncm91cCA9IHJvd25hbWVzKG1lcmdlX21hdHJpeCkpDQpkaWFnKG1lcmdlX21hdHJpeDIpIDwtIDAgICMgcmVtb3ZlIGRpYWdvbmFsIGlmIHlvdSBkbyBub3Qgd2FudCB3aXRoaW4tY29udGluZW50IGNvbGxhYm9yYXRpb25zDQoNCiMgQ3JlYXRlIHRoZSBjaG9yZCBkaWFncmFtDQpjaG9yZERpYWdyYW1Gcm9tTWF0cml4KG1lcmdlX21hdHJpeDIpDQoNCiMgT3B0aW9uYWxseSBkZWZpbmUgY29sb3IgcGFsZXR0ZQ0KbXlfY29sb3JzIDwtIGMoIiMxQjlFNzciLCAiI0Q5NUYwMiIsICIjNzU3MEIzIiwgIiNFNkFCMDIiKQ0KbXlfY29sb3JzIDwtIHJlcChteV9jb2xvcnMsIGxlbmd0aC5vdXQgPSBuY29sKG1lcmdlX21hdHJpeDIpKQ0KDQpqcGVnKCJmaWd1cmVzL2NvbnRpbmVudF9jaG9yZF9kaWFncmFtLmpwZyIsIHdpZHRoID0gMjUsIGhlaWdodCA9IDI1LCB1bml0cyA9ICJjbSIsIHJlcyA9IDMwMCkNCg0KIyBEcmF3IGNob3JkIGRpYWdyYW0gd2l0aCBzb21lIHN0eWxpbmcNCmNob3JkRGlhZ3JhbShtZXJnZV9tYXRyaXgyLCANCiAgICAgICAgICAgICBhbm5vdGF0aW9uVHJhY2sgPSAiZ3JpZCIsIA0KICAgICAgICAgICAgIGFubm90YXRpb25UcmFja0hlaWdodCA9IG1tX2goNyksIA0KICAgICAgICAgICAgIHByZUFsbG9jYXRlVHJhY2tzID0gMSwNCiAgICAgICAgICAgICBncmlkLmNvbCA9IG15X2NvbG9ycykNCg0KIyBBZGQgdHJhY2sgdG8gbGFiZWwgZWFjaCBzZWN0b3INCmNpcmNvcy50cmFja1Bsb3RSZWdpb24odHJhY2suaW5kZXggPSAxLCBwYW5lbC5mdW4gPSBmdW5jdGlvbih4LCB5KSB7DQogIHhsaW0gICAgICAgPSBnZXQuY2VsbC5tZXRhLmRhdGEoInhsaW0iKQ0KICB5bGltICAgICAgID0gZ2V0LmNlbGwubWV0YS5kYXRhKCJ5bGltIikNCiAgc2VjdG9yLm5hbWU9IGdldC5jZWxsLm1ldGEuZGF0YSgic2VjdG9yLmluZGV4IikNCiAgY2lyY29zLnRleHQobWVhbih4bGltKSwgeWxpbVsxXSwgc2VjdG9yLm5hbWUsIA0KICAgICAgICAgICAgICBmYWNpbmcgPSAiYmVuZGluZy5pbnNpZGUiLCBuaWNlRmFjaW5nID0gVFJVRSwgDQogICAgICAgICAgICAgIGFkaiA9IGMoMC41LCAxLjc1KSwgY29sID0gIndoaXRlIiwgY2V4ID0gMS4yKQ0KfSwgYmcuYm9yZGVyID0gTkEpDQoNCmRldi5vZmYoKQ0KDQpgYGANCg0K